diff --git a/404.html b/404.html index 4803b5521..5c74bcea3 100644 --- a/404.html +++ b/404.html @@ -15,7 +15,7 @@ - + @@ -43,7 +43,7 @@ GitHub (opens new window) GitHub - (opens new window)

404 - Not Found

There's nothing here.
+ (opens new window)

404 - Not Found

Looks like we've got some broken links.
Take me home.
- + diff --git a/assets/img/blue-wallet.fb035b79.png b/assets/img/blue-wallet.fb035b79.png deleted file mode 100644 index 34eece845..000000000 Binary files a/assets/img/blue-wallet.fb035b79.png and /dev/null differ diff --git a/assets/img/mutiny.5939a956.svg b/assets/img/mutiny.5939a956.svg deleted file mode 100644 index c3a51afc3..000000000 --- a/assets/img/mutiny.5939a956.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/assets/js/1.020b21ec.js b/assets/js/1.05bb713a.js similarity index 90% rename from assets/js/1.020b21ec.js rename to assets/js/1.05bb713a.js index bacdb2597..279545e90 100644 --- a/assets/js/1.020b21ec.js +++ b/assets/js/1.05bb713a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{252:function(t,e,s){"use strict";s.d(e,"d",(function(){return n})),s.d(e,"a",(function(){return r})),s.d(e,"i",(function(){return a})),s.d(e,"f",(function(){return l})),s.d(e,"g",(function(){return u})),s.d(e,"h",(function(){return c})),s.d(e,"b",(function(){return h})),s.d(e,"e",(function(){return p})),s.d(e,"k",(function(){return d})),s.d(e,"l",(function(){return f})),s.d(e,"c",(function(){return m})),s.d(e,"j",(function(){return b}));s(46);const n=/#.*$/,i=/\.(md|html)$/,r=/\/$/,a=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(n,"").replace(i,"")}function l(t){return a.test(t)}function u(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(l(t))return t;const e=t.match(n),s=e?e[0]:"",i=o(t);return r.test(i)?t:i+".html"+s}function p(t,e){const s=decodeURIComponent(t.hash),i=function(t){const e=t.match(n);if(e)return e[0]}(e);if(i&&s!==i)return!1;return o(t.path)===o(e)}function d(t,e,s){if(l(e))return{type:"external",path:e};s&&(e=function(t,e,s){const n=t.charAt(0);if("/"===n)return t;if("?"===n||"#"===n)return e+t;const i=e.split("/");s&&i[i.length-1]||i.pop();const r=t.replace(/^\//,"").split("/");for(let t=0;tfunction t(e,s,n,i=1){if("string"==typeof e)return d(s,e,n);if(Array.isArray(e))return Object.assign(d(s,e[0],n),{title:e[1]});{const r=e.children||[];return 0===r.length&&e.path?Object.assign(d(s,e.path,n),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:r.map(e=>t(e,s,n,i+1)),collapsable:!1!==e.collapsable}}}(t,i,s)):[]}return[]}function g(t){const e=m(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map(e=>({type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}))}]}function m(t){let e;return(t=t.map(t=>Object.assign({},t))).forEach(t=>{2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)}),t.filter(t=>2===t.level)}function b(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},259:function(t,e,s){"use strict";s(329),s(330),s(331),s(46);var n={name:"AlgoliaSearchBox",props:["options"],data:()=>({placeholder:void 0}),watch:{$lang(t){this.update(this.options,t)},options(t){this.update(t,this.$lang)}},mounted(){this.initialize(this.options,this.$lang),this.placeholder=this.$site.themeConfig.searchPlaceholder||""},methods:{initialize(t,e){Promise.all([Promise.all([s.e(0),s.e(3)]).then(s.t.bind(null,375,7)),Promise.all([s.e(0),s.e(3)]).then(s.t.bind(null,376,7))]).then(([s])=>{s=s.default;const{algoliaOptions:n={}}=t;s(Object.assign({},t,{inputSelector:"#algolia-search-input",algoliaOptions:{...n,facetFilters:["lang:"+e].concat(n.facetFilters||[])},handleSelected:(t,e,s)=>{const{pathname:n,hash:i}=new URL(s.url),r=n.replace(this.$site.base,"/"),a=decodeURIComponent(i);this.$router.push(`${r}${a}`)}}))})},update(t,e){this.$el.innerHTML='',this.initialize(t,e)}}},i=(s(333),s(7)),r=Object(i.a)(n,(function(){var t=this._self._c;return t("form",{staticClass:"algolia-search-wrapper search-box",attrs:{id:"search-form",role:"search"}},[t("input",{staticClass:"search-query",attrs:{id:"algolia-search-input",placeholder:this.placeholder}})])}),[],!1,null,null,null).exports,a=s(110),o=s.n(a),l=(t,e,s=null)=>{let n=o()(e,"title","");return o()(e,"frontmatter.tags")&&(n+=" "+e.frontmatter.tags.join(" ")),s&&(n+=" "+s),u(t,n)};const u=(t,e)=>{const s=t=>t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),n=new RegExp("[^\0-]"),i=t.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t);if(n.test(t))return i.some(t=>e.toLowerCase().indexOf(t)>-1);{const n=t.endsWith(" ");return new RegExp(i.map((t,e)=>i.length!==e+1||n?`(?=.*\\b${s(t)}\\b)`:`(?=.*\\b${s(t)})`).join("")+".+","gi").test(e)}};var c={name:"SearchBox",data:()=>({query:"",focused:!1,focusIndex:0,placeholder:void 0}),computed:{showSuggestions(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions(){const t=this.query.trim().toLowerCase();if(!t)return;const{pages:e}=this.$site,s=this.$site.themeConfig.searchMaxSuggestions||5,n=this.$localePath,i=[];for(let r=0;r=s);r++){const a=e[r];if(this.getPageLocalePath(a)===n&&this.isSearchable(a))if(l(t,a))i.push(a);else if(a.headers)for(let e=0;e=s);e++){const s=a.headers[e];s.title&&l(t,a,s.title)&&i.push(Object.assign({},a,{path:a.path+"#"+s.slug,header:s}))}}return i},alignRight(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath(t){for(const e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable(t){let e=null;return null===e||(e=Array.isArray(e)?e:new Array(e),e.filter(e=>t.path.match(e)).length>0)},onHotkey(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown(){this.showSuggestions&&(this.focusIndex "+t._s(s.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),p=(s(335),Object(i.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[e("svg",{staticClass:"icon",attrs:{viewBox:"0 0 40 40",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img"}},[e("g",{staticClass:"hamburger",attrs:{fill:"currentColor"}},[e("path",{attrs:{d:"M33.75 11.6699H6.25C5.55964 11.6699 5 12.2296 5 12.9199C5 13.6103 5.55964 14.1699 6.25 14.1699H33.75C34.4404 14.1699 35 13.6103 35 12.9199C35 12.2296 34.4404 11.6699 33.75 11.6699Z"}}),t._v(" "),e("path",{attrs:{d:"M28.75 18.752H6.25C5.55964 18.752 5 19.3116 5 20.002C5 20.6923 5.55964 21.252 6.25 21.252H28.75C29.4404 21.252 30 20.6923 30 20.002C30 19.3116 29.4404 18.752 28.75 18.752Z"}}),t._v(" "),e("path",{attrs:{d:"M33.75 25.8301H6.25C5.55964 25.8301 5 26.3897 5 27.0801C5 27.7704 5.55964 28.3301 6.25 28.3301H33.75C34.4404 28.3301 35 27.7704 35 27.0801C35 26.3897 34.4404 25.8301 33.75 25.8301Z"}})]),t._v(" "),e("g",{staticClass:"close",attrs:{stroke:"currentColor"}},[e("path",{attrs:{d:"M10 10L30 30","stroke-width":"2","stroke-linecap":"round"}}),t._v(" "),e("path",{attrs:{d:"M30 10L10 30","stroke-width":"2","stroke-linecap":"round"}})])])])}),[],!1,null,null,null).exports),d=s(279),f=s(328),g=s(111),m=s.n(g),b={name:"DropdownLink",components:{NavLink:d.a,DropdownTransition:f.a},props:{item:{required:!0}},data:()=>({open:!1}),computed:{dropdownAriaLabel(){return this.item.ariaLabel||this.item.text}},watch:{$route(){this.open=!1}},methods:{setOpen(t){this.open=t},isLastItemOfArray:(t,e)=>m()(e)===t,handleDropdown(){0===event.detail&&this.setOpen(!this.open)}}},v=(s(337),Object(i.a)(b,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[e("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[e("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),e("span",{staticClass:"arrow down"})]),t._v(" "),e("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[e("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),e("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),e("DropdownTransition",[e("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(s,n){return e("li",{key:s.link||n,staticClass:"dropdown-item"},["links"===s.type?e("h4",[t._v("\n "+t._s(s.text)+"\n ")]):t._e(),t._v(" "),"links"===s.type?e("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(s.items,(function(n){return e("li",{key:n.link,staticClass:"dropdown-subitem"},[e("NavLink",{attrs:{item:n},on:{focusout:function(e){t.isLastItemOfArray(n,s.items)&&t.isLastItemOfArray(s,t.item.items)&&t.setOpen(!1)}}})],1)})),0):e("NavLink",{attrs:{item:s},on:{focusout:function(e){t.isLastItemOfArray(s,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports),C=s(252),k={name:"NavLinks",components:{NavLink:d.a,DropdownLink:v},computed:{userNav(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav(){const{locales:t}=this.$site;if(t&&Object.keys(t).length>1){const e=this.$page.path,s=this.$router.options.routes,n=this.$site.themeConfig.locales||{},i={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(t).map(i=>{const r=t[i],a=n[i]&&n[i].label||r.lang;let o;return r.lang===this.$lang?o=e:(o=e.replace(this.$localeConfig.path,i),s.some(t=>t.path===o)||(o=i)),{text:a,link:o}})};return[...this.userNav,i]}return this.userNav},userLinks(){return(this.nav||[]).map(t=>Object.assign(Object(C.j)(t),{items:(t.items||[]).map(C.j)}))},repoLink(){const{repo:t}=this.$site.themeConfig;return t?/^https?:/.test(t)?t:"https://github.com/"+t:null},repoLabel(){if(!this.repoLink)return;if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;const t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"];for(let s=0;s({linksWrapMaxWidth:null}),computed:{algolia(){return this.$themeLocaleConfig.algolia||this.$site.themeConfig.algolia||{}},isAlgoliaSearch(){return this.algolia&&this.algolia.apiKey&&this.algolia.indexName}},mounted(){const t=parseInt(y(this.$el,"paddingLeft"))+parseInt(y(this.$el,"paddingRight")),e=()=>{document.documentElement.clientWidth<719?this.linksWrapMaxWidth=null:this.linksWrapMaxWidth=this.$el.offsetWidth-t-(this.$refs.siteName&&this.$refs.siteName.offsetWidth||0)};e(),window.addEventListener("resize",e,!1)},methods:{toggleColorMode(t){t.preventDefault();const e=(document.documentElement.getAttribute(w.THEME_ATTR)||w.COLOR_MODES[0])===w.COLOR_MODES[0]?w.COLOR_MODES[1]:w.COLOR_MODES[0];Object(w.setColorMode)(e)}}},L=(s(339),Object(i.a)(x,(function(){var t=this,e=t._self._c;return e("header",{staticClass:"navbar"},[e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("RouterLink",{staticClass:"home-link",attrs:{to:t.$localePath}},[t.$site.themeConfig.logo?e("svg",{staticClass:"logo",attrs:{role:"img",alt:t.$siteTitle}},[e("use",{staticClass:"small",attrs:{href:t.$withBase(t.$site.themeConfig.logo)+"#small"}}),t._v(" "),e("use",{staticClass:"large",attrs:{href:t.$withBase(t.$site.themeConfig.logo)+"#large"}})]):t._e()]),t._v(" "),e("div",{staticClass:"links",style:t.linksWrapMaxWidth?{"max-width":t.linksWrapMaxWidth+"px"}:{}},[e("NavLinks",{staticClass:"can-hide"}),t._v(" "),t.isAlgoliaSearch?e("AlgoliaSearchBox",{attrs:{options:t.algolia}}):!1!==t.$site.themeConfig.search&&!1!==t.$page.frontmatter.search?e("SearchBox"):t._e(),t._v(" "),e("button",{staticClass:"theme-switch",attrs:{type:"button"},on:{click:function(e){return t.toggleColorMode(e)}}},[e("svg",{attrs:{viewBox:"0 0 30 31",fill:"none",xmlns:"http://www.w3.org/2000/svg"}},[e("g",{staticClass:"theme-switch-dark"},[e("path",{attrs:{d:"M15 20.4219C12.5187 20.4219 10.5 18.4032 10.5 15.9219C10.5 13.4406 12.5187 11.4219 15 11.4219C17.4813 11.4219 19.5 13.4406 19.5 15.9219C19.5 18.4032 17.4813 20.4219 15 20.4219Z",fill:"currentColor"}}),t._v(" "),e("path",{attrs:{d:"M19.4541 20.3769L21.3644 22.2862M15 24.9219V22.2219V24.9219ZM15 9.62187V6.92188V9.62187ZM6 15.9219H8.7H6ZM21.3 15.9219H24H21.3ZM8.6361 22.2862L10.5454 20.3769L8.6361 22.2862ZM19.4541 11.4678L21.3644 9.55797L19.4541 11.4678ZM8.6361 9.55797L10.5454 11.4678L8.6361 9.55797Z",stroke:"currentColor","stroke-width":"1","stroke-linecap":"round"}})]),t._v(" "),e("g",{staticClass:"theme-switch-light",attrs:{fill:"currentColor"}},[e("path",{attrs:{d:"M10.1539 8.75585C10.018 8.75585 9.88774 8.70189 9.79168 8.60583C9.69563 8.50977 9.64166 8.37949 9.64166 8.24365V6.19482C9.64166 6.05898 9.69563 5.9287 9.79168 5.83264C9.88774 5.73658 10.018 5.68262 10.1539 5.68262C10.2897 5.68262 10.42 5.73658 10.5161 5.83264C10.6121 5.9287 10.6661 6.05898 10.6661 6.19482V8.24365C10.6661 8.37949 10.6121 8.50977 10.5161 8.60583C10.42 8.70189 10.2897 8.75585 10.1539 8.75585Z"}}),t._v(" "),e("path",{attrs:{d:"M11.1783 7.73144H9.12945C8.9936 7.73144 8.86332 7.67748 8.76726 7.58142C8.6712 7.48536 8.61724 7.35508 8.61724 7.21924C8.61724 7.08339 8.6712 6.95311 8.76726 6.85705C8.86332 6.761 8.9936 6.70703 9.12945 6.70703H11.1783C11.3141 6.70703 11.4444 6.761 11.5405 6.85705C11.6365 6.95311 11.6905 7.08339 11.6905 7.21924C11.6905 7.35508 11.6365 7.48536 11.5405 7.58142C11.4444 7.67748 11.3141 7.73144 11.1783 7.73144ZM6.05621 13.8779C5.92037 13.8779 5.79009 13.8239 5.69403 13.7279C5.59797 13.6318 5.54401 13.5015 5.54401 13.3657V12.3413C5.54401 12.2054 5.59797 12.0752 5.69403 11.9791C5.79009 11.8831 5.92037 11.8291 6.05621 11.8291C6.19206 11.8291 6.32234 11.8831 6.4184 11.9791C6.51445 12.0752 6.56842 12.2054 6.56842 12.3413V13.3657C6.56842 13.5015 6.51445 13.6318 6.4184 13.7279C6.32234 13.8239 6.19206 13.8779 6.05621 13.8779Z"}}),t._v(" "),e("path",{attrs:{d:"M6.56842 13.366H5.544C5.40816 13.366 5.27788 13.312 5.18182 13.216C5.08576 13.1199 5.0318 12.9896 5.0318 12.8538C5.0318 12.7179 5.08576 12.5877 5.18182 12.4916C5.27788 12.3955 5.40816 12.3416 5.544 12.3416H6.56842C6.70426 12.3416 6.83454 12.3955 6.9306 12.4916C7.02666 12.5877 7.08062 12.7179 7.08062 12.8538C7.08062 12.9896 7.02666 13.1199 6.9306 13.216C6.83454 13.312 6.70426 13.366 6.56842 13.366ZM16.8125 23.6101C12.8583 23.6101 9.64165 20.3934 9.64165 16.4392C9.64165 12.8983 12.2851 9.85021 15.7907 9.34876L16.4658 9.25195L16.37 9.92755C16.326 10.218 16.3027 10.5112 16.3003 10.805C16.3003 14.1942 19.0575 16.9514 22.4468 16.9514C22.708 16.9514 22.9872 16.9294 23.3247 16.8813L23.9998 16.7855L23.9035 17.4606C23.401 20.9666 20.3524 23.6101 16.8125 23.6101Z"}})])])])],1),t._v(" "),e("SidebarButton",{on:{"toggle-sidebar":function(e){return t.$emit("toggle-sidebar")}}})],1)])])}),[],!1,null,null,null).exports),$={name:"Sidebar",components:{SidebarLinks:s(327).default,NavLinks:_},props:["items"]},O=(s(342),Object(i.a)($,(function(){var t=this._self._c;return t("aside",{staticClass:"sidebar"},[t("NavLinks"),this._v(" "),this._t("top"),this._v(" "),t("SidebarLinks",{attrs:{depth:0,items:this.items}}),this._v(" "),this._t("bottom")],2)}),[],!1,null,null,null).exports),S={name:"Footer",components:{NavLink:d.a},computed:{links(){return this.$site.themeConfig.footer.links},copyright(){return this.$site.themeConfig.footer.copyright}}},j=(s(343),{name:"Layout",components:{Sidebar:O,Navbar:L,Footer:Object(i.a)(S,(function(){var t=this,e=t._self._c;return e("footer",{staticClass:"footer"},[e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("div",{staticClass:"inner"},[e("div",{staticClass:"footer-content"},t._l(t.links,(function(s){return e("div",{key:s.title,staticClass:"footer-block"},[e("h4",[t._v(t._s(s.title))]),t._v(" "),t._l(s.children,(function(t){return e("div",{key:t.link},[e("NavLink",{attrs:{item:t}})],1)}))],2)})),0),t._v(" "),t.copyright?e("p",{staticClass:"copyright"},[t._v(t._s(t.copyright))]):t._e()])])])])}),[],!1,null,null,null).exports},data:()=>({isSidebarOpen:!1}),computed:{shouldShowNavbar(){const{themeConfig:t}=this.$site,{frontmatter:e}=this.$page;return!1!==e.navbar&&!1!==t.navbar&&(this.$title||t.logo||t.repo||t.nav||this.$themeLocaleConfig.nav)},shouldShowSidebar(){const{frontmatter:t}=this.$page;return!t.home&&!1!==t.sidebar&&this.sidebarItems.length},sidebarItems(){return Object(C.l)(this.$page,this.$page.regularPath,this.$site,this.$localePath)},pageClasses(){const t=this.$page.frontmatter.pageClass;return[{"no-navbar":!this.shouldShowNavbar,"sidebar-open":this.isSidebarOpen,"no-sidebar":!this.shouldShowSidebar},t]}},mounted(){this.$router.afterEach(()=>{this.isSidebarOpen=!1})},methods:{toggleSidebar(t){this.isSidebarOpen="boolean"==typeof t?t:!this.isSidebarOpen,this.$emit("toggle-sidebar",this.isSidebarOpen)},onTouchStart(t){this.touchStart={x:t.changedTouches[0].clientX,y:t.changedTouches[0].clientY}},onTouchEnd(t){const e=t.changedTouches[0].clientX-this.touchStart.x,s=t.changedTouches[0].clientY-this.touchStart.y;Math.abs(e)>Math.abs(s)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),I=(s(344),Object(i.a)(j,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?e("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),e("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t._t("default")],2)]),t._v(" "),e("Footer")],1)}),[],!1,null,"b812d5fc",null));e.a=I.exports},279:function(t,e,s){"use strict";var n=s(252),i={name:"NavLink",props:{item:{required:!0}},computed:{link(){return Object(n.b)(this.item.link)},exact(){return this.$site.locales?Object.keys(this.$site.locales).some(t=>t===this.link):"/"===this.link},isNonHttpURI(){return Object(n.g)(this.link)||Object(n.h)(this.link)},isBlankTarget(){return"_blank"===this.target},isInternal(){return!Object(n.f)(this.link)&&!this.isBlankTarget},target(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(n.f)(this.link)?"_blank":""},rel(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction(){this.$emit("focusout")}}},r=s(7),a=Object(r.a)(i,(function(){var t=this,e=t._self._c;return t.isInternal?e("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):e("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?e("OutboundLink"):t._e()],1)}),[],!1,null,null,null);e.a=a.exports},288:function(t,e,s){"use strict";var n=TypeError;t.exports=function(t,e){if(t2&&(r.style={"padding-left":i+"rem"}),t("RouterLink",r,s)}function u(t,e,s,n,r,a=1){return!e||a>r?null:t("ul",{class:"sidebar-sub-headers"},e.map(e=>{const o=Object(i.e)(n,s+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[l(t,s+"#"+e.slug,e.title,o,e.level-1),u(t,e.children,s,n,r,a+1)])}))}var c={functional:!0,props:["item","sidebarDepth"],render(t,{parent:{$page:e,$site:s,$route:n,$themeConfig:r,$themeLocaleConfig:a},props:{item:o,sidebarDepth:c}}){const h=Object(i.e)(n,o.path),p="auto"===o.type?h||o.children.some(t=>Object(i.e)(n,o.basePath+"#"+t.slug)):h,d="external"===o.type?function(t,e,s){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[s,t("OutboundLink")])}(t,o.path,o.title||o.path):l(t,o.path,o.title||o.path,p),f=[e.frontmatter.sidebarDepth,c,a.sidebarDepth,r.sidebarDepth,1].find(t=>void 0!==t),g=a.displayAllHeaders||r.displayAllHeaders;if("auto"===o.type)return[d,u(t,o.children,o.basePath,n,f)];if((p||g)&&o.headers&&!i.d.test(o.path)){return[d,u(t,Object(i.c)(o.headers),o.path,n,f)]}return d}};s(341);function h(t,e){if("group"===e.type){const s=e.path&&Object(i.e)(t,e.path),n=e.children.some(e=>"group"===e.type?h(t,e):"page"===e.type&&Object(i.e)(t,e.path));return s||n}return!1}var p={name:"SidebarLinks",components:{SidebarGroup:o,SidebarLink:Object(a.a)(c,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route(){this.refreshIndex()}},created(){this.refreshIndex()},methods:{refreshIndex(){const t=function(t,e){for(let s=0;s-1&&(this.openGroupIndex=t)},toggleGroup(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive(t){return Object(i.e)(this.$route,t.regularPath)}}},d=Object(a.a)(p,(function(){var t=this,e=t._self._c;return t.items.length?e("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(s,n){return e("li",{key:n},["group"===s.type?e("SidebarGroup",{attrs:{item:s,open:n===t.openGroupIndex,collapsable:s.collapsable||s.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(n)}}}):e("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:s}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=d.exports},328:function(t,e,s){"use strict";var n={name:"DropdownTransition",methods:{setHeight(t){t.style.height=t.scrollHeight+"px"},unsetHeight(t){t.style.height=""}}},i=(s(336),s(7)),r=Object(i.a)(n,(function(){return(0,this._self._c)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=r.exports},329:function(t,e,s){"use strict";var n=s(106),i=s(2),r=s(107),a=s(288),o=URLSearchParams,l=o.prototype,u=i(l.append),c=i(l.delete),h=i(l.forEach),p=i([].push),d=new o("a=1&a=2&b=3");d.delete("a",1),d.delete("b",void 0),d+""!="a=2"&&n(l,"delete",(function(t){var e=arguments.length,s=e<2?void 0:arguments[1];if(e&&void 0===s)return c(this,t);var n=[];h(this,(function(t,e){p(n,{key:e,value:t})})),a(e,1);for(var i,o=r(t),l=r(s),d=0,f=0,g=!1,m=n.length;dfunction t(e,s,n,i=1){if("string"==typeof e)return d(s,e,n);if(Array.isArray(e))return Object.assign(d(s,e[0],n),{title:e[1]});{const r=e.children||[];return 0===r.length&&e.path?Object.assign(d(s,e.path,n),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:r.map(e=>t(e,s,n,i+1)),collapsable:!1!==e.collapsable}}}(t,i,s)):[]}return[]}function g(t){const e=m(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map(e=>({type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}))}]}function m(t){let e;return(t=t.map(t=>Object.assign({},t))).forEach(t=>{2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)}),t.filter(t=>2===t.level)}function b(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},259:function(t,e,s){"use strict";s(328),s(329),s(330),s(46);var n={name:"AlgoliaSearchBox",props:["options"],data:()=>({placeholder:void 0}),watch:{$lang(t){this.update(this.options,t)},options(t){this.update(t,this.$lang)}},mounted(){this.initialize(this.options,this.$lang),this.placeholder=this.$site.themeConfig.searchPlaceholder||""},methods:{initialize(t,e){Promise.all([Promise.all([s.e(0),s.e(3)]).then(s.t.bind(null,373,7)),Promise.all([s.e(0),s.e(3)]).then(s.t.bind(null,374,7))]).then(([s])=>{s=s.default;const{algoliaOptions:n={}}=t;s(Object.assign({},t,{inputSelector:"#algolia-search-input",algoliaOptions:{...n,facetFilters:["lang:"+e].concat(n.facetFilters||[])},handleSelected:(t,e,s)=>{const{pathname:n,hash:i}=new URL(s.url),r=n.replace(this.$site.base,"/"),a=decodeURIComponent(i);this.$router.push(`${r}${a}`)}}))})},update(t,e){this.$el.innerHTML='',this.initialize(t,e)}}},i=(s(332),s(7)),r=Object(i.a)(n,(function(){var t=this._self._c;return t("form",{staticClass:"algolia-search-wrapper search-box",attrs:{id:"search-form",role:"search"}},[t("input",{staticClass:"search-query",attrs:{id:"algolia-search-input",placeholder:this.placeholder}})])}),[],!1,null,null,null).exports,a=s(110),o=s.n(a),l=(t,e,s=null)=>{let n=o()(e,"title","");return o()(e,"frontmatter.tags")&&(n+=" "+e.frontmatter.tags.join(" ")),s&&(n+=" "+s),u(t,n)};const u=(t,e)=>{const s=t=>t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),n=new RegExp("[^\0-]"),i=t.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t);if(n.test(t))return i.some(t=>e.toLowerCase().indexOf(t)>-1);{const n=t.endsWith(" ");return new RegExp(i.map((t,e)=>i.length!==e+1||n?`(?=.*\\b${s(t)}\\b)`:`(?=.*\\b${s(t)})`).join("")+".+","gi").test(e)}};var c={name:"SearchBox",data:()=>({query:"",focused:!1,focusIndex:0,placeholder:void 0}),computed:{showSuggestions(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions(){const t=this.query.trim().toLowerCase();if(!t)return;const{pages:e}=this.$site,s=this.$site.themeConfig.searchMaxSuggestions||5,n=this.$localePath,i=[];for(let r=0;r=s);r++){const a=e[r];if(this.getPageLocalePath(a)===n&&this.isSearchable(a))if(l(t,a))i.push(a);else if(a.headers)for(let e=0;e=s);e++){const s=a.headers[e];s.title&&l(t,a,s.title)&&i.push(Object.assign({},a,{path:a.path+"#"+s.slug,header:s}))}}return i},alignRight(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath(t){for(const e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable(t){let e=null;return null===e||(e=Array.isArray(e)?e:new Array(e),e.filter(e=>t.path.match(e)).length>0)},onHotkey(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown(){this.showSuggestions&&(this.focusIndex "+t._s(s.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),p=(s(334),Object(i.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[e("svg",{staticClass:"icon",attrs:{viewBox:"0 0 40 40",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img"}},[e("g",{staticClass:"hamburger",attrs:{fill:"currentColor"}},[e("path",{attrs:{d:"M33.75 11.6699H6.25C5.55964 11.6699 5 12.2296 5 12.9199C5 13.6103 5.55964 14.1699 6.25 14.1699H33.75C34.4404 14.1699 35 13.6103 35 12.9199C35 12.2296 34.4404 11.6699 33.75 11.6699Z"}}),t._v(" "),e("path",{attrs:{d:"M28.75 18.752H6.25C5.55964 18.752 5 19.3116 5 20.002C5 20.6923 5.55964 21.252 6.25 21.252H28.75C29.4404 21.252 30 20.6923 30 20.002C30 19.3116 29.4404 18.752 28.75 18.752Z"}}),t._v(" "),e("path",{attrs:{d:"M33.75 25.8301H6.25C5.55964 25.8301 5 26.3897 5 27.0801C5 27.7704 5.55964 28.3301 6.25 28.3301H33.75C34.4404 28.3301 35 27.7704 35 27.0801C35 26.3897 34.4404 25.8301 33.75 25.8301Z"}})]),t._v(" "),e("g",{staticClass:"close",attrs:{stroke:"currentColor"}},[e("path",{attrs:{d:"M10 10L30 30","stroke-width":"2","stroke-linecap":"round"}}),t._v(" "),e("path",{attrs:{d:"M30 10L10 30","stroke-width":"2","stroke-linecap":"round"}})])])])}),[],!1,null,null,null).exports),d=s(279),f=s(327),g=s(111),m=s.n(g),b={name:"DropdownLink",components:{NavLink:d.a,DropdownTransition:f.a},props:{item:{required:!0}},data:()=>({open:!1}),computed:{dropdownAriaLabel(){return this.item.ariaLabel||this.item.text}},watch:{$route(){this.open=!1}},methods:{setOpen(t){this.open=t},isLastItemOfArray:(t,e)=>m()(e)===t,handleDropdown(){0===event.detail&&this.setOpen(!this.open)}}},v=(s(336),Object(i.a)(b,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[e("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[e("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),e("span",{staticClass:"arrow down"})]),t._v(" "),e("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[e("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),e("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),e("DropdownTransition",[e("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(s,n){return e("li",{key:s.link||n,staticClass:"dropdown-item"},["links"===s.type?e("h4",[t._v("\n "+t._s(s.text)+"\n ")]):t._e(),t._v(" "),"links"===s.type?e("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(s.items,(function(n){return e("li",{key:n.link,staticClass:"dropdown-subitem"},[e("NavLink",{attrs:{item:n},on:{focusout:function(e){t.isLastItemOfArray(n,s.items)&&t.isLastItemOfArray(s,t.item.items)&&t.setOpen(!1)}}})],1)})),0):e("NavLink",{attrs:{item:s},on:{focusout:function(e){t.isLastItemOfArray(s,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports),C=s(252),k={name:"NavLinks",components:{NavLink:d.a,DropdownLink:v},computed:{userNav(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav(){const{locales:t}=this.$site;if(t&&Object.keys(t).length>1){const e=this.$page.path,s=this.$router.options.routes,n=this.$site.themeConfig.locales||{},i={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(t).map(i=>{const r=t[i],a=n[i]&&n[i].label||r.lang;let o;return r.lang===this.$lang?o=e:(o=e.replace(this.$localeConfig.path,i),s.some(t=>t.path===o)||(o=i)),{text:a,link:o}})};return[...this.userNav,i]}return this.userNav},userLinks(){return(this.nav||[]).map(t=>Object.assign(Object(C.j)(t),{items:(t.items||[]).map(C.j)}))},repoLink(){const{repo:t}=this.$site.themeConfig;return t?/^https?:/.test(t)?t:"https://github.com/"+t:null},repoLabel(){if(!this.repoLink)return;if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;const t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"];for(let s=0;s({linksWrapMaxWidth:null}),computed:{algolia(){return this.$themeLocaleConfig.algolia||this.$site.themeConfig.algolia||{}},isAlgoliaSearch(){return this.algolia&&this.algolia.apiKey&&this.algolia.indexName}},mounted(){const t=parseInt(y(this.$el,"paddingLeft"))+parseInt(y(this.$el,"paddingRight")),e=()=>{document.documentElement.clientWidth<719?this.linksWrapMaxWidth=null:this.linksWrapMaxWidth=this.$el.offsetWidth-t-(this.$refs.siteName&&this.$refs.siteName.offsetWidth||0)};e(),window.addEventListener("resize",e,!1)},methods:{toggleColorMode(t){t.preventDefault();const e=(document.documentElement.getAttribute(w.THEME_ATTR)||w.COLOR_MODES[0])===w.COLOR_MODES[0]?w.COLOR_MODES[1]:w.COLOR_MODES[0];Object(w.setColorMode)(e)}}},L=(s(338),Object(i.a)(x,(function(){var t=this,e=t._self._c;return e("header",{staticClass:"navbar"},[e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("RouterLink",{staticClass:"home-link",attrs:{to:t.$localePath}},[t.$site.themeConfig.logo?e("svg",{staticClass:"logo",attrs:{role:"img",alt:t.$siteTitle}},[e("use",{staticClass:"small",attrs:{href:t.$withBase(t.$site.themeConfig.logo)+"#small"}}),t._v(" "),e("use",{staticClass:"large",attrs:{href:t.$withBase(t.$site.themeConfig.logo)+"#large"}})]):t._e()]),t._v(" "),e("div",{staticClass:"links",style:t.linksWrapMaxWidth?{"max-width":t.linksWrapMaxWidth+"px"}:{}},[e("NavLinks",{staticClass:"can-hide"}),t._v(" "),t.isAlgoliaSearch?e("AlgoliaSearchBox",{attrs:{options:t.algolia}}):!1!==t.$site.themeConfig.search&&!1!==t.$page.frontmatter.search?e("SearchBox"):t._e(),t._v(" "),e("button",{staticClass:"theme-switch",attrs:{type:"button"},on:{click:function(e){return t.toggleColorMode(e)}}},[e("svg",{attrs:{viewBox:"0 0 30 31",fill:"none",xmlns:"http://www.w3.org/2000/svg"}},[e("g",{staticClass:"theme-switch-dark"},[e("path",{attrs:{d:"M15 20.4219C12.5187 20.4219 10.5 18.4032 10.5 15.9219C10.5 13.4406 12.5187 11.4219 15 11.4219C17.4813 11.4219 19.5 13.4406 19.5 15.9219C19.5 18.4032 17.4813 20.4219 15 20.4219Z",fill:"currentColor"}}),t._v(" "),e("path",{attrs:{d:"M19.4541 20.3769L21.3644 22.2862M15 24.9219V22.2219V24.9219ZM15 9.62187V6.92188V9.62187ZM6 15.9219H8.7H6ZM21.3 15.9219H24H21.3ZM8.6361 22.2862L10.5454 20.3769L8.6361 22.2862ZM19.4541 11.4678L21.3644 9.55797L19.4541 11.4678ZM8.6361 9.55797L10.5454 11.4678L8.6361 9.55797Z",stroke:"currentColor","stroke-width":"1","stroke-linecap":"round"}})]),t._v(" "),e("g",{staticClass:"theme-switch-light",attrs:{fill:"currentColor"}},[e("path",{attrs:{d:"M10.1539 8.75585C10.018 8.75585 9.88774 8.70189 9.79168 8.60583C9.69563 8.50977 9.64166 8.37949 9.64166 8.24365V6.19482C9.64166 6.05898 9.69563 5.9287 9.79168 5.83264C9.88774 5.73658 10.018 5.68262 10.1539 5.68262C10.2897 5.68262 10.42 5.73658 10.5161 5.83264C10.6121 5.9287 10.6661 6.05898 10.6661 6.19482V8.24365C10.6661 8.37949 10.6121 8.50977 10.5161 8.60583C10.42 8.70189 10.2897 8.75585 10.1539 8.75585Z"}}),t._v(" "),e("path",{attrs:{d:"M11.1783 7.73144H9.12945C8.9936 7.73144 8.86332 7.67748 8.76726 7.58142C8.6712 7.48536 8.61724 7.35508 8.61724 7.21924C8.61724 7.08339 8.6712 6.95311 8.76726 6.85705C8.86332 6.761 8.9936 6.70703 9.12945 6.70703H11.1783C11.3141 6.70703 11.4444 6.761 11.5405 6.85705C11.6365 6.95311 11.6905 7.08339 11.6905 7.21924C11.6905 7.35508 11.6365 7.48536 11.5405 7.58142C11.4444 7.67748 11.3141 7.73144 11.1783 7.73144ZM6.05621 13.8779C5.92037 13.8779 5.79009 13.8239 5.69403 13.7279C5.59797 13.6318 5.54401 13.5015 5.54401 13.3657V12.3413C5.54401 12.2054 5.59797 12.0752 5.69403 11.9791C5.79009 11.8831 5.92037 11.8291 6.05621 11.8291C6.19206 11.8291 6.32234 11.8831 6.4184 11.9791C6.51445 12.0752 6.56842 12.2054 6.56842 12.3413V13.3657C6.56842 13.5015 6.51445 13.6318 6.4184 13.7279C6.32234 13.8239 6.19206 13.8779 6.05621 13.8779Z"}}),t._v(" "),e("path",{attrs:{d:"M6.56842 13.366H5.544C5.40816 13.366 5.27788 13.312 5.18182 13.216C5.08576 13.1199 5.0318 12.9896 5.0318 12.8538C5.0318 12.7179 5.08576 12.5877 5.18182 12.4916C5.27788 12.3955 5.40816 12.3416 5.544 12.3416H6.56842C6.70426 12.3416 6.83454 12.3955 6.9306 12.4916C7.02666 12.5877 7.08062 12.7179 7.08062 12.8538C7.08062 12.9896 7.02666 13.1199 6.9306 13.216C6.83454 13.312 6.70426 13.366 6.56842 13.366ZM16.8125 23.6101C12.8583 23.6101 9.64165 20.3934 9.64165 16.4392C9.64165 12.8983 12.2851 9.85021 15.7907 9.34876L16.4658 9.25195L16.37 9.92755C16.326 10.218 16.3027 10.5112 16.3003 10.805C16.3003 14.1942 19.0575 16.9514 22.4468 16.9514C22.708 16.9514 22.9872 16.9294 23.3247 16.8813L23.9998 16.7855L23.9035 17.4606C23.401 20.9666 20.3524 23.6101 16.8125 23.6101Z"}})])])])],1),t._v(" "),e("SidebarButton",{on:{"toggle-sidebar":function(e){return t.$emit("toggle-sidebar")}}})],1)])])}),[],!1,null,null,null).exports),$={name:"Sidebar",components:{SidebarLinks:s(326).default,NavLinks:_},props:["items"]},O=(s(341),Object(i.a)($,(function(){var t=this._self._c;return t("aside",{staticClass:"sidebar"},[t("NavLinks"),this._v(" "),this._t("top"),this._v(" "),t("SidebarLinks",{attrs:{depth:0,items:this.items}}),this._v(" "),this._t("bottom")],2)}),[],!1,null,null,null).exports),S={name:"Footer",components:{NavLink:d.a},computed:{links(){return this.$site.themeConfig.footer.links},copyright(){return this.$site.themeConfig.footer.copyright}}},j=(s(342),{name:"Layout",components:{Sidebar:O,Navbar:L,Footer:Object(i.a)(S,(function(){var t=this,e=t._self._c;return e("footer",{staticClass:"footer"},[e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("div",{staticClass:"inner"},[e("div",{staticClass:"footer-content"},t._l(t.links,(function(s){return e("div",{key:s.title,staticClass:"footer-block"},[e("h4",[t._v(t._s(s.title))]),t._v(" "),t._l(s.children,(function(t){return e("div",{key:t.link},[e("NavLink",{attrs:{item:t}})],1)}))],2)})),0),t._v(" "),t.copyright?e("p",{staticClass:"copyright"},[t._v(t._s(t.copyright))]):t._e()])])])])}),[],!1,null,null,null).exports},data:()=>({isSidebarOpen:!1}),computed:{shouldShowNavbar(){const{themeConfig:t}=this.$site,{frontmatter:e}=this.$page;return!1!==e.navbar&&!1!==t.navbar&&(this.$title||t.logo||t.repo||t.nav||this.$themeLocaleConfig.nav)},shouldShowSidebar(){const{frontmatter:t}=this.$page;return!t.home&&!1!==t.sidebar&&this.sidebarItems.length},sidebarItems(){return Object(C.l)(this.$page,this.$page.regularPath,this.$site,this.$localePath)},pageClasses(){const t=this.$page.frontmatter.pageClass;return[{"no-navbar":!this.shouldShowNavbar,"sidebar-open":this.isSidebarOpen,"no-sidebar":!this.shouldShowSidebar},t]}},mounted(){this.$router.afterEach(()=>{this.isSidebarOpen=!1})},methods:{toggleSidebar(t){this.isSidebarOpen="boolean"==typeof t?t:!this.isSidebarOpen,this.$emit("toggle-sidebar",this.isSidebarOpen)},onTouchStart(t){this.touchStart={x:t.changedTouches[0].clientX,y:t.changedTouches[0].clientY}},onTouchEnd(t){const e=t.changedTouches[0].clientX-this.touchStart.x,s=t.changedTouches[0].clientY-this.touchStart.y;Math.abs(e)>Math.abs(s)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),I=(s(343),Object(i.a)(j,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?e("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),e("div",{staticClass:"wrap"},[e("div",{staticClass:"wrap-border"},[e("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),e("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t._t("default")],2)]),t._v(" "),e("Footer")],1)}),[],!1,null,"b812d5fc",null));e.a=I.exports},279:function(t,e,s){"use strict";var n=s(252),i={name:"NavLink",props:{item:{required:!0}},computed:{link(){return Object(n.b)(this.item.link)},exact(){return this.$site.locales?Object.keys(this.$site.locales).some(t=>t===this.link):"/"===this.link},isNonHttpURI(){return Object(n.g)(this.link)||Object(n.h)(this.link)},isBlankTarget(){return"_blank"===this.target},isInternal(){return!Object(n.f)(this.link)&&!this.isBlankTarget},target(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(n.f)(this.link)?"_blank":""},rel(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction(){this.$emit("focusout")}}},r=s(7),a=Object(r.a)(i,(function(){var t=this,e=t._self._c;return t.isInternal?e("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):e("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?e("OutboundLink"):t._e()],1)}),[],!1,null,null,null);e.a=a.exports},289:function(t,e,s){"use strict";var n=TypeError;t.exports=function(t,e){if(t2&&(r.style={"padding-left":i+"rem"}),t("RouterLink",r,s)}function u(t,e,s,n,r,a=1){return!e||a>r?null:t("ul",{class:"sidebar-sub-headers"},e.map(e=>{const o=Object(i.e)(n,s+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[l(t,s+"#"+e.slug,e.title,o,e.level-1),u(t,e.children,s,n,r,a+1)])}))}var c={functional:!0,props:["item","sidebarDepth"],render(t,{parent:{$page:e,$site:s,$route:n,$themeConfig:r,$themeLocaleConfig:a},props:{item:o,sidebarDepth:c}}){const h=Object(i.e)(n,o.path),p="auto"===o.type?h||o.children.some(t=>Object(i.e)(n,o.basePath+"#"+t.slug)):h,d="external"===o.type?function(t,e,s){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[s,t("OutboundLink")])}(t,o.path,o.title||o.path):l(t,o.path,o.title||o.path,p),f=[e.frontmatter.sidebarDepth,c,a.sidebarDepth,r.sidebarDepth,1].find(t=>void 0!==t),g=a.displayAllHeaders||r.displayAllHeaders;if("auto"===o.type)return[d,u(t,o.children,o.basePath,n,f)];if((p||g)&&o.headers&&!i.d.test(o.path)){return[d,u(t,Object(i.c)(o.headers),o.path,n,f)]}return d}};s(340);function h(t,e){if("group"===e.type){const s=e.path&&Object(i.e)(t,e.path),n=e.children.some(e=>"group"===e.type?h(t,e):"page"===e.type&&Object(i.e)(t,e.path));return s||n}return!1}var p={name:"SidebarLinks",components:{SidebarGroup:o,SidebarLink:Object(a.a)(c,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route(){this.refreshIndex()}},created(){this.refreshIndex()},methods:{refreshIndex(){const t=function(t,e){for(let s=0;s-1&&(this.openGroupIndex=t)},toggleGroup(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive(t){return Object(i.e)(this.$route,t.regularPath)}}},d=Object(a.a)(p,(function(){var t=this,e=t._self._c;return t.items.length?e("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(s,n){return e("li",{key:n},["group"===s.type?e("SidebarGroup",{attrs:{item:s,open:n===t.openGroupIndex,collapsable:s.collapsable||s.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(n)}}}):e("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:s}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=d.exports},327:function(t,e,s){"use strict";var n={name:"DropdownTransition",methods:{setHeight(t){t.style.height=t.scrollHeight+"px"},unsetHeight(t){t.style.height=""}}},i=(s(335),s(7)),r=Object(i.a)(n,(function(){return(0,this._self._c)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=r.exports},328:function(t,e,s){"use strict";var n=s(106),i=s(2),r=s(107),a=s(289),o=URLSearchParams,l=o.prototype,u=i(l.append),c=i(l.delete),h=i(l.forEach),p=i([].push),d=new o("a=1&a=2&b=3");d.delete("a",1),d.delete("b",void 0),d+""!="a=2"&&n(l,"delete",(function(t){var e=arguments.length,s=e<2?void 0:arguments[1];if(e&&void 0===s)return c(this,t);var n=[];h(this,(function(t,e){p(n,{key:e,value:t})})),a(e,1);for(var i,o=r(t),l=r(s),d=0,f=0,g=!1,m=n.length;dt,getPageLinkConfig:({frontmatter:t})=>t.next},PREV:{resolveLink:function(t,e){return v(t,e,-1)},getThemeLinkConfig:({prevLinks:t})=>t,getPageLinkConfig:({frontmatter:t})=>t.prev}};function h(t,{$themeConfig:e,$page:a,$route:n,$site:r,sidebarItems:o}){const{resolveLink:l,getThemeLinkConfig:c,getPageLinkConfig:u}=t,d=c(e),h=u(a),v=i()(h)?d:h;return!1===v?void 0:p()(v)?Object(s.k)(r.pages,v,n.path):l(a,o)}function v(t,e,a){const n=[];!function t(e,a){for(let n=0,i=e.length;nt,getPageLinkConfig:({frontmatter:t})=>t.next},PREV:{resolveLink:function(t,e){return v(t,e,-1)},getThemeLinkConfig:({prevLinks:t})=>t,getPageLinkConfig:({frontmatter:t})=>t.prev}};function h(t,{$themeConfig:e,$page:a,$route:n,$site:r,sidebarItems:o}){const{resolveLink:l,getThemeLinkConfig:c,getPageLinkConfig:u}=t,d=c(e),h=u(a),v=i()(h)?d:h;return!1===v?void 0:p()(v)?Object(s.k)(r.pages,v,n.path):l(a,o)}function v(t,e,a){const n=[];!function t(e,a){for(let n=0,i=e.length;n")])])])]),A._v(" "),I("div",{staticClass:"cross-promo"},[I("a",{attrs:{href:"https://bitcoindevkit.org/"}},[I("div",{staticClass:"cross-promo-inner"},[I("img",{attrs:{src:g(368)}}),A._v(" "),I("div",{staticClass:"divider"}),A._v(" "),I("p",{staticClass:"cross-promo-description"},[A._v("The on-chain companion to LDK")])])])])])}),[],!1,null,null,null);I.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/11.9c6b1526.js b/assets/js/11.9c6b1526.js new file mode 100644 index 000000000..574c0156a --- /dev/null +++ b/assets/js/11.9c6b1526.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{280:function(A,I,g){A.exports=g.p+"assets/img/alby.d8538ae1.svg"},281:function(A,I){A.exports="data:image/png;base64,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"},365:function(A,I,g){A.exports=g.p+"assets/img/bitkit.783e1405.svg"},366:function(A,I,g){A.exports=g.p+"assets/img/cashapp.db7a02f3.svg"},367:function(A,I,g){A.exports=g.p+"assets/img/bdk-logo.ea5ab41d.svg"},424:function(A,I,g){"use strict";g.r(I);var C=g(7),t=Object(C.a)({},(function(){var A=this,I=A._self._c;return I("ContentSlotsDistributor",{attrs:{"slot-key":A.$parent.slotKey}},[I("div",{staticClass:"case-studies"},[I("div",{staticClass:"case-studies-inner"},[I("div",{staticClass:"logo-wrapper"},[I("img",{attrs:{src:g(365)}}),A._v(" "),I("img",{attrs:{src:g(280)}}),A._v(" "),I("img",{attrs:{src:g(366)}}),A._v(" "),I("img",{attrs:{src:g(281)}})]),A._v(" "),I("div",{staticClass:"case-studies-inner-content"},[I("h1",[A._v("Trusted by the best")]),A._v(" "),I("p",{staticClass:"description"},[A._v("Innovative projects are building with LDK")]),A._v(" "),I("a",{attrs:{href:"/case-studies/"}},[A._v("All case studies ->")])])])]),A._v(" "),I("div",{staticClass:"cross-promo"},[I("a",{attrs:{href:"https://bitcoindevkit.org/"}},[I("div",{staticClass:"cross-promo-inner"},[I("img",{attrs:{src:g(367)}}),A._v(" "),I("div",{staticClass:"divider"}),A._v(" "),I("p",{staticClass:"cross-promo-description"},[A._v("The on-chain companion to LDK")])])])])])}),[],!1,null,null,null);I.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/12.dd68cbd1.js b/assets/js/12.42d55a59.js similarity index 98% rename from assets/js/12.dd68cbd1.js rename to assets/js/12.42d55a59.js index bb9e2933f..88fb4bb57 100644 --- a/assets/js/12.dd68cbd1.js +++ b/assets/js/12.42d55a59.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{350:function(t,a,n){t.exports=n.p+"assets/img/qr-codes.58a16df5.png"},351:function(t,a,n){t.exports=n.p+"assets/img/blinded-path.2f9b76cf.svg"},352:function(t,a,n){t.exports=n.p+"assets/img/offers-flow.ccc79cd7.svg"},353:function(t,a,n){t.exports=n.p+"assets/img/offer-metadata.45a2a1cf.svg"},392:function(t,a,n){"use strict";n.r(a);var s=n(7),e=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("You may have heard of BOLT12—lovingly referred to as Offers—but what is it, and why should you care? In short, BOLT12 is a new payment protocol for Lightning that offers enhanced privacy, reusable payment codes, refunds, and much more, all natively over the Lightning Network. No additional servers are required. This is all possible using new technologies like onion messages and route blinding. Let’s further explore how to make use of BOLT12 in LDK.")]),t._v(" "),a("h2",{attrs:{id:"bolt11-invoices-and-reusability"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#bolt11-invoices-and-reusability"}},[t._v("#")]),t._v(" BOLT11 Invoices and Reusability")]),t._v(" "),a("p",[t._v("To understand why BOLT12 is essential, let’s briefly discuss what it’s replacing. BOLT11 defined an invoice format that, while useful, has some shortcomings. Invoices are communicated out-of-band—typically via a QR code—from recipient to sender. They are signed, making them large and thus difficult for some devices to scan. But more importantly, they can’t be safely reused since they contain a payment hash.")]),t._v(" "),a("p",[t._v("In Lightning, a payment is claimed by releasing the preimage of a payment hash. Once revealed, anyone with knowledge of the preimage—which could show up on-chain—may use it to claim a payment for an invoice using the same payment hash. So, reusing invoices is a no-no if you don’t want your payment stolen. While solutions have been built up around BOLT11 for requesting unique invoices, they have significant drawbacks. It requires either running a dedicated server or trusting a third party to do so on your behalf, including all the privacy implications that this entails.")]),t._v(" "),a("h2",{attrs:{id:"bolt12-to-the-rescue"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#bolt12-to-the-rescue"}},[t._v("#")]),t._v(" BOLT12 to the Rescue")]),t._v(" "),a("p",[t._v("That’s where BOLT12 comes in. The specification defines an "),a("em",[t._v("offer")]),t._v(" that can be considered a precursor to an "),a("em",[t._v("invoice")]),t._v(". It contains less data than an invoice and is smaller to display as a QR code. Optionally, it may contain blinded paths—more on that in a moment. Someone scanning an offer sends an "),a("em",[t._v("invoice request")]),t._v(" to the intended recipient, who replies with an invoice containing a unique payment hash. That’s it!")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(350),alt:"BOLT11 vs BOLT12 QR Codes"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Comparison of typical BOLT11 (left) and BOLT12 (right) QR codes")])]),t._v(" "),a("p",[t._v("So how is this all happening without a dedicated server? The magic comes in with something called "),a("a",{attrs:{href:"../onion-messages-demystified"}},[t._v("onion messages")]),t._v(". The Lightning protocol is defined as messages exchanged between direct peers. An onion payment involves an interchange of messages along a path, collecting fees and transferring funds until the preimage is revealed and the funds claimed.")]),t._v(" "),a("p",[t._v("An onion message is very similar in that it involves sending messages along a path, encrypted as an onion such that each hop only knows where to send the message next. The difference is that they’re more efficient and don’t require locking any liquidity. Messages are forwarded until they reach the intended recipient. There is no interchange between adjacent peers to sign and revoke commitments or a round-trip along the path. Channel liquidity—or channels, for that matter—aren’t even required.")]),t._v(" "),a("h2",{attrs:{id:"ok-so-what-about-privacy"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ok-so-what-about-privacy"}},[t._v("#")]),t._v(" OK, so what about privacy?")]),t._v(" "),a("p",[t._v("Ah, that’s where blinded paths come in. BOLT11 invoices reveal the recipient's node ID, which could be mapped to their IP address. But remember how an offer may contain some blinded paths? Those are to ensure recipient privacy. The recipient constructs a path leading to itself from some point in the Lightning Network, probably a few hops away. Then, it blinds the nodes along the route using fancy cryptography, leaving the first node unblinded. We call that the introduction node.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(351),alt:"Blinded Path"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Depiction of a blinded path used in an offer where adjacent nodes are peers")])]),t._v(" "),a("p",[t._v("When the sender scans an offer, it constructs a path from itself to the blinded path’s introduction node. This combined path is then made into an onion for routing with the invoice request as the payload. It also contains a "),a("em",[t._v("reply path")]),t._v("—another blinded path—back to the sender, allowing the recipient to respond similarly to an invoice without revealing the sender’s node ID.")]),t._v(" "),a("p",[t._v("This is taken further with the invoice, which contains "),a("em",[t._v("blinded payment paths")]),t._v("—essentially blinded paths with some additional payment information. This allows the recipient to provide partial routes with enough liquidity for payment as requests are made—yet in a privacy-preserving manner, unlike BOLT11.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(352),alt:"Offers flow"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Offers flow of Alice paying Bob where onion messages and payments culminate over blinded paths")])]),t._v(" "),a("p",[t._v("Invoices and invoice requests are signed using keys corresponding to pubkeys in the offer and invoice request. But guess what? These can be unique since, in the presence of blinded paths, they aren’t needed for routing. By always generating new keys, payments are more difficult to correlate to the same sender or recipient, an added boon for privacy! Contrast this with a BOLT11 invoice containing the recipient’s node ID. This is so the sender can construct a route to the recipient for the payment.")]),t._v(" "),a("h2",{attrs:{id:"offers-in-ldk"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#offers-in-ldk"}},[t._v("#")]),t._v(" Offers in LDK")]),t._v(" "),a("p",[t._v("There’s a lot to BOLT12, but LDK helpfully hides all those details from you. Let’s take a look at how you would construct an offer in LDK using the familiar builder pattern.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" offer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_offer_builder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("description")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"coffee"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("amount_msats")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10_000_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bech32_offer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" offer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("One cool thing about offers is that they can be stateless, meaning you don’t need to store any data about them once constructed. How does this work? LDK encodes some information in the offer’s metadata, allowing it to recognize incoming invoice requests for the offer.")]),t._v(" "),a("p",[t._v("Paying an offer is just as simple.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" retry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Timeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("pay_for_offer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n offer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" quantity"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msats"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payer_note"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" retry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max_total_routing_fee_msat\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Requesting invoice for offer"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Unable to request invoice for offer: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// First the payment will be waiting on an invoice")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" expected_payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_recent_payments")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("details"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("matches!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n details"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RecentPaymentDetails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AwaitingInvoice")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expected_payment_id "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("is_some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Once the invoice is received, a payment will be sent")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_recent_payments")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("details"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("matches!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n details"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RecentPaymentDetails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expected_payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("is_some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Here, LDK stores a small amount of data for outbound payments, which ensures you don’t pay an invoice more than once for a given payment ID.")]),t._v(" "),a("p",[t._v("As the recipient, you only need to wait for an event to claim the payment.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[t._v("channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("process_pending_events")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" purpose"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" purpose "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt12OfferPayment")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Claiming payment {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt12OfferPayment")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Unknown payment hash: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Claimed {} msats"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Similarly, the sender will receive an event when the payment is resolved.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[t._v("channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("process_pending_events")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Paid {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed paying {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvoiceRequestFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed paying {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("These examples work swimmingly when building a Lightning wallet programmatically. However, LDK uniquely exposes the underlying "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/offers/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("offers"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/blinded_path/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("blinded paths"),a("OutboundLink")],1),t._v(", and "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/onion_message/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("onion message"),a("OutboundLink")],1),t._v(" modules for direct use. This means you can experiment with building your applications or add BOLT12 support to LND, such as the "),a("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank",rel:"noopener noreferrer"}},[t._v("LNDK"),a("OutboundLink")],1),t._v(" project.")]),t._v(" "),a("h2",{attrs:{id:"wait-what-about-refunds"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#wait-what-about-refunds"}},[t._v("#")]),t._v(" Wait, what about refunds?")]),t._v(" "),a("p",[t._v("Whereas an offer is an “offer to be paid,” a "),a("em",[t._v("refund")]),t._v(" is an “offer for money.” Simply put, refunds allow a merchant to present a QR code to a customer to refund a purchase. The customer scans the refund just like it would an offer, but instead of sending the merchant an invoice request, the customer sends an invoice asking the merchant to pay.")]),t._v(" "),a("p",[t._v("LDK has a similar interface for constructing a refund and requesting payment.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" retry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Timeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" refund "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_refund_builder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n amount_msats"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" absolute_expiry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" retry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max_total_routing_fee_msat\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("description")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"coffee"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payer_note")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"refund for order 1234"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bech32_refund "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" refund"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Like when paying an offer, LDK will track a pending payment and surface events just the same. However, for inbound payments the events will use "),a("code",[t._v("PaymentPurpose::Bolt12RefundPayment")]),t._v(" instead.")]),t._v(" "),a("h2",{attrs:{id:"achieving-statelessness"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#achieving-statelessness"}},[t._v("#")]),t._v(" Achieving statelessness")]),t._v(" "),a("p",[t._v("Both offer and invoice requests contain a metadata field. This helps LDK store minimal information about a payment. For inbound payments, this equals nothing at all! So how does it work?")]),t._v(" "),a("p",[t._v("LDK generates a random nonce for an offer and, along with the offer’s TLV records, computes an HMAC using a secret key. The HMAC is used to derive a key to sign the invoice. The nonce is then stored in the offer’s metadata to re-derive the signing key later.")]),t._v(" "),a("p",[t._v("When an invoice request is received, it contains all the offer’s TLV records, including the metadata. By re-deriving the signing key from the metadata and TLV records, LDK can verify that the offer is authentic by checking whether the re-derived signing key corresponds to the offer’s signing pubkey. Now, it can create and sign an invoice with the key.")]),t._v(" "),a("p",[t._v("If you prefer to use your signing key, LDK will also include the HMAC in the metadata. Authentication then consists of re-computing the HMAC and comparing it against the one in the metadata.")]),t._v(" "),a("p",[t._v("An invoice request has its own payer metadata, which is similarly generated and includes an encrypted payment ID. Thus, when LDK receives an invoice, it can look up a pending payment with the ID and decide if the invoice should be paid after a similar authentication.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(353),alt:"Offer metadata"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Metadata consists primarily of a nonce and an optional HMAC, while outbound payments include an encrypted payment ID used for look-up upon receiving an invoice")])]),t._v(" "),a("h2",{attrs:{id:"what-s-next"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-s-next"}},[t._v("#")]),t._v(" What’s next?")]),t._v(" "),a("p",[t._v("BOLT12 is still in a very early stage of adoption, but as you can see, there’s much promise. In the next post, we’ll explore one of the most crucial problems in Lightning—receiving offline—and how BOLT12 and asynchronous payments solve it.")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{348:function(t,a,n){t.exports=n.p+"assets/img/qr-codes.58a16df5.png"},349:function(t,a,n){t.exports=n.p+"assets/img/blinded-path.2f9b76cf.svg"},350:function(t,a,n){t.exports=n.p+"assets/img/offers-flow.ccc79cd7.svg"},351:function(t,a,n){t.exports=n.p+"assets/img/offer-metadata.45a2a1cf.svg"},389:function(t,a,n){"use strict";n.r(a);var s=n(7),e=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("You may have heard of BOLT12—lovingly referred to as Offers—but what is it, and why should you care? In short, BOLT12 is a new payment protocol for Lightning that offers enhanced privacy, reusable payment codes, refunds, and much more, all natively over the Lightning Network. No additional servers are required. This is all possible using new technologies like onion messages and route blinding. Let’s further explore how to make use of BOLT12 in LDK.")]),t._v(" "),a("h2",{attrs:{id:"bolt11-invoices-and-reusability"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#bolt11-invoices-and-reusability"}},[t._v("#")]),t._v(" BOLT11 Invoices and Reusability")]),t._v(" "),a("p",[t._v("To understand why BOLT12 is essential, let’s briefly discuss what it’s replacing. BOLT11 defined an invoice format that, while useful, has some shortcomings. Invoices are communicated out-of-band—typically via a QR code—from recipient to sender. They are signed, making them large and thus difficult for some devices to scan. But more importantly, they can’t be safely reused since they contain a payment hash.")]),t._v(" "),a("p",[t._v("In Lightning, a payment is claimed by releasing the preimage of a payment hash. Once revealed, anyone with knowledge of the preimage—which could show up on-chain—may use it to claim a payment for an invoice using the same payment hash. So, reusing invoices is a no-no if you don’t want your payment stolen. While solutions have been built up around BOLT11 for requesting unique invoices, they have significant drawbacks. It requires either running a dedicated server or trusting a third party to do so on your behalf, including all the privacy implications that this entails.")]),t._v(" "),a("h2",{attrs:{id:"bolt12-to-the-rescue"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#bolt12-to-the-rescue"}},[t._v("#")]),t._v(" BOLT12 to the Rescue")]),t._v(" "),a("p",[t._v("That’s where BOLT12 comes in. The specification defines an "),a("em",[t._v("offer")]),t._v(" that can be considered a precursor to an "),a("em",[t._v("invoice")]),t._v(". It contains less data than an invoice and is smaller to display as a QR code. Optionally, it may contain blinded paths—more on that in a moment. Someone scanning an offer sends an "),a("em",[t._v("invoice request")]),t._v(" to the intended recipient, who replies with an invoice containing a unique payment hash. That’s it!")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(348),alt:"BOLT11 vs BOLT12 QR Codes"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Comparison of typical BOLT11 (left) and BOLT12 (right) QR codes")])]),t._v(" "),a("p",[t._v("So how is this all happening without a dedicated server? The magic comes in with something called "),a("a",{attrs:{href:"../onion-messages-demystified"}},[t._v("onion messages")]),t._v(". The Lightning protocol is defined as messages exchanged between direct peers. An onion payment involves an interchange of messages along a path, collecting fees and transferring funds until the preimage is revealed and the funds claimed.")]),t._v(" "),a("p",[t._v("An onion message is very similar in that it involves sending messages along a path, encrypted as an onion such that each hop only knows where to send the message next. The difference is that they’re more efficient and don’t require locking any liquidity. Messages are forwarded until they reach the intended recipient. There is no interchange between adjacent peers to sign and revoke commitments or a round-trip along the path. Channel liquidity—or channels, for that matter—aren’t even required.")]),t._v(" "),a("h2",{attrs:{id:"ok-so-what-about-privacy"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ok-so-what-about-privacy"}},[t._v("#")]),t._v(" OK, so what about privacy?")]),t._v(" "),a("p",[t._v("Ah, that’s where blinded paths come in. BOLT11 invoices reveal the recipient's node ID, which could be mapped to their IP address. But remember how an offer may contain some blinded paths? Those are to ensure recipient privacy. The recipient constructs a path leading to itself from some point in the Lightning Network, probably a few hops away. Then, it blinds the nodes along the route using fancy cryptography, leaving the first node unblinded. We call that the introduction node.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(349),alt:"Blinded Path"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Depiction of a blinded path used in an offer where adjacent nodes are peers")])]),t._v(" "),a("p",[t._v("When the sender scans an offer, it constructs a path from itself to the blinded path’s introduction node. This combined path is then made into an onion for routing with the invoice request as the payload. It also contains a "),a("em",[t._v("reply path")]),t._v("—another blinded path—back to the sender, allowing the recipient to respond similarly to an invoice without revealing the sender’s node ID.")]),t._v(" "),a("p",[t._v("This is taken further with the invoice, which contains "),a("em",[t._v("blinded payment paths")]),t._v("—essentially blinded paths with some additional payment information. This allows the recipient to provide partial routes with enough liquidity for payment as requests are made—yet in a privacy-preserving manner, unlike BOLT11.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(350),alt:"Offers flow"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Offers flow of Alice paying Bob where onion messages and payments culminate over blinded paths")])]),t._v(" "),a("p",[t._v("Invoices and invoice requests are signed using keys corresponding to pubkeys in the offer and invoice request. But guess what? These can be unique since, in the presence of blinded paths, they aren’t needed for routing. By always generating new keys, payments are more difficult to correlate to the same sender or recipient, an added boon for privacy! Contrast this with a BOLT11 invoice containing the recipient’s node ID. This is so the sender can construct a route to the recipient for the payment.")]),t._v(" "),a("h2",{attrs:{id:"offers-in-ldk"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#offers-in-ldk"}},[t._v("#")]),t._v(" Offers in LDK")]),t._v(" "),a("p",[t._v("There’s a lot to BOLT12, but LDK helpfully hides all those details from you. Let’s take a look at how you would construct an offer in LDK using the familiar builder pattern.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" offer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_offer_builder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("description")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"coffee"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("amount_msats")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10_000_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bech32_offer "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" offer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("One cool thing about offers is that they can be stateless, meaning you don’t need to store any data about them once constructed. How does this work? LDK encodes some information in the offer’s metadata, allowing it to recognize incoming invoice requests for the offer.")]),t._v(" "),a("p",[t._v("Paying an offer is just as simple.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" retry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Timeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("pay_for_offer")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n offer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" quantity"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msats"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payer_note"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" retry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max_total_routing_fee_msat\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Requesting invoice for offer"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Unable to request invoice for offer: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// First the payment will be waiting on an invoice")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" expected_payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_recent_payments")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("details"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("matches!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n details"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RecentPaymentDetails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AwaitingInvoice")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expected_payment_id "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("is_some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Once the invoice is received, a payment will be sent")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_recent_payments")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("details"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("matches!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n details"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RecentPaymentDetails")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expected_payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("is_some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Here, LDK stores a small amount of data for outbound payments, which ensures you don’t pay an invoice more than once for a given payment ID.")]),t._v(" "),a("p",[t._v("As the recipient, you only need to wait for an event to claim the payment.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[t._v("channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("process_pending_events")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" purpose"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" purpose "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt12OfferPayment")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Claiming payment {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt12OfferPayment")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Unknown payment hash: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Claimed {} msats"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Similarly, the sender will receive an event when the payment is resolved.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[t._v("channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("process_pending_events")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Paid {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed paying {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvoiceRequestFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed paying {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("These examples work swimmingly when building a Lightning wallet programmatically. However, LDK uniquely exposes the underlying "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/offers/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("offers"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/blinded_path/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("blinded paths"),a("OutboundLink")],1),t._v(", and "),a("a",{attrs:{href:"https://docs.rs/lightning/0.0.123/lightning/onion_message/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("onion message"),a("OutboundLink")],1),t._v(" modules for direct use. This means you can experiment with building your applications or add BOLT12 support to LND, such as the "),a("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank",rel:"noopener noreferrer"}},[t._v("LNDK"),a("OutboundLink")],1),t._v(" project.")]),t._v(" "),a("h2",{attrs:{id:"wait-what-about-refunds"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#wait-what-about-refunds"}},[t._v("#")]),t._v(" Wait, what about refunds?")]),t._v(" "),a("p",[t._v("Whereas an offer is an “offer to be paid,” a "),a("em",[t._v("refund")]),t._v(" is an “offer for money.” Simply put, refunds allow a merchant to present a QR code to a customer to refund a purchase. The customer scans the refund just like it would an offer, but instead of sending the merchant an invoice request, the customer sends an invoice asking the merchant to pay.")]),t._v(" "),a("p",[t._v("LDK has a similar interface for constructing a refund and requesting payment.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" retry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Timeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" refund "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_refund_builder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n amount_msats"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" absolute_expiry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" retry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max_total_routing_fee_msat\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("description")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"coffee"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payer_note")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"refund for order 1234"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bech32_refund "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" refund"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("Like when paying an offer, LDK will track a pending payment and surface events just the same. However, for inbound payments the events will use "),a("code",[t._v("PaymentPurpose::Bolt12RefundPayment")]),t._v(" instead.")]),t._v(" "),a("h2",{attrs:{id:"achieving-statelessness"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#achieving-statelessness"}},[t._v("#")]),t._v(" Achieving statelessness")]),t._v(" "),a("p",[t._v("Both offer and invoice requests contain a metadata field. This helps LDK store minimal information about a payment. For inbound payments, this equals nothing at all! So how does it work?")]),t._v(" "),a("p",[t._v("LDK generates a random nonce for an offer and, along with the offer’s TLV records, computes an HMAC using a secret key. The HMAC is used to derive a key to sign the invoice. The nonce is then stored in the offer’s metadata to re-derive the signing key later.")]),t._v(" "),a("p",[t._v("When an invoice request is received, it contains all the offer’s TLV records, including the metadata. By re-deriving the signing key from the metadata and TLV records, LDK can verify that the offer is authentic by checking whether the re-derived signing key corresponds to the offer’s signing pubkey. Now, it can create and sign an invoice with the key.")]),t._v(" "),a("p",[t._v("If you prefer to use your signing key, LDK will also include the HMAC in the metadata. Authentication then consists of re-computing the HMAC and comparing it against the one in the metadata.")]),t._v(" "),a("p",[t._v("An invoice request has its own payer metadata, which is similarly generated and includes an encrypted payment ID. Thus, when LDK receives an invoice, it can look up a pending payment with the ID and decide if the invoice should be paid after a similar authentication.")]),t._v(" "),a("figure",[a("img",{attrs:{src:n(351),alt:"Offer metadata"}})]),t._v(" "),a("p",{staticStyle:{"text-align":"center"}},[a("i",[t._v("Metadata consists primarily of a nonce and an optional HMAC, while outbound payments include an encrypted payment ID used for look-up upon receiving an invoice")])]),t._v(" "),a("h2",{attrs:{id:"what-s-next"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-s-next"}},[t._v("#")]),t._v(" What’s next?")]),t._v(" "),a("p",[t._v("BOLT12 is still in a very early stage of adoption, but as you can see, there’s much promise. In the next post, we’ll explore one of the most crucial problems in Lightning—receiving offline—and how BOLT12 and asynchronous payments solve it.")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/13.d5fdf55e.js b/assets/js/13.163d6eb7.js similarity index 99% rename from assets/js/13.d5fdf55e.js rename to assets/js/13.163d6eb7.js index 5fce43f11..4533a63a7 100644 --- a/assets/js/13.d5fdf55e.js +++ b/assets/js/13.163d6eb7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{358:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-1.8264e375.png"},359:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-2.e3e05fcb.png"},360:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-3.fd401501.png"},361:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-4.934aee81.png"},398:function(e,t,n){"use strict";n.r(t);var o=n(7),s=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("We recently merged support for onion message forwarding, a precursor to deprecating today’s Lightning invoice format, in favor of "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/798",target:"_blank",rel:"noopener noreferrer"}},[e._v("offers"),t("OutboundLink")],1),e._v(". Offers bring many improvements to Lightning, including static invoices, refunds, and receiving payments in a way that doesn’t reveal your node ID or UTXOs. Then, once offer extensions are added, support for subscriptions follows.")]),e._v(" "),t("p",[e._v("So a lot is happening. Including…")]),e._v(" "),t("p",[e._v("Once the network supports "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/ptlc/",target:"_blank",rel:"noopener noreferrer"}},[e._v("PTLCs"),t("OutboundLink")],1),e._v(", onion messages will help enable "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("asynchronous Lightning payments"),t("OutboundLink")],1),e._v(" that remove the rule requiring nodes to be online when receiving payments. We expect onion messages to provide a better foundation for noncustodial Lightning payment UX, including privacy bonuses.")]),e._v(" "),t("h2",{attrs:{id:"how-onion-messages-work"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#how-onion-messages-work"}},[e._v("#")]),e._v(" How Onion Messages Work")]),e._v(" "),t("p",[e._v("Onion messages are lightweight, flexible messages sent between Lightning Network peers using onion routing. Unlike today’s payment messages, peers may send onion messages along a blinded route, thus concealing the recipient’s info. But what’s a blinded route?")]),e._v(" "),t("h2",{attrs:{id:"blinded-routes"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#blinded-routes"}},[e._v("#")]),e._v(" Blinded Routes")]),e._v(" "),t("p",[e._v("If Alice doesn’t want to reveal lots of personal information about her channels and UTXOs, she can use cryptography to create an obfuscated or “blinded” route to herself for the sender (we’ll call him Bob) to send an onion message along. To construct this route, she’ll first find a route to herself from some PopularNode in the graph that has a lot of peers.")]),e._v(" "),t("p",[e._v("By selecting PopularNode from this network chart, Alice’s anonymity set includes all highlighted peers:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(358),alt:"OM"}})]),e._v(" "),t("p",[e._v("To Bob and any other observers, any node within two hops of PopularNode could be the destination of the onion message. Adding more hops further expands Alice’s anonymity set. (Note that PopularNode’s direct peers are candidates because blinded routes may contain fake dummy hops.)")]),e._v(" "),t("p",[e._v("After selecting the path from PopularNode, she’ll create an encrypted blob for each hop that contains information about reaching the next hop, which ends at her node. At this point, the blinded route looks like this:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(359),alt:"OM"}})]),e._v(" "),t("p",[e._v("Finally, she’ll provide this blinded route to Bob, who will find a route to PopularNode and use Alice’s blinded route when constructing the last three hop payloads within the onion packet.")]),e._v(" "),t("h2",{attrs:{id:"onion-message-structure"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#onion-message-structure"}},[e._v("#")]),e._v(" Onion Message Structure")]),e._v(" "),t("p",[e._v("Continuing with this example, let’s say Bob finds this path to Alice’s blinded route:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(360),alt:"OM"}})]),e._v(" "),t("p",[e._v("If Bob sends an invoice request through Alice’s blinded route via onion message, his message would look like this:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(361),alt:"OM"}})]),e._v(" "),t("p",[e._v("So each intermediate layer of the onion contains encrypted forwarding information for the next hop, and the last layer contains the content of the onion message intended for the final hop. This content may include invoice requests and invoices for offers.")]),e._v(" "),t("h2",{attrs:{id:"beyond-offers-asynchronous-payments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#beyond-offers-asynchronous-payments"}},[e._v("#")]),e._v(" Beyond Offers: Asynchronous Payments")]),e._v(" "),t("p",[e._v("While offers were the original point of onion messages, their flexible format unlocks further opportunities to improve the Lightning Network.")]),e._v(" "),t("p",[e._v("For context, a significant problem facing the Lightning Network is that users running noncustodial Lightning wallets on phones must have their wallet app in the foreground to receive payments. This is a big departure from the Cash App-like UX that users want and even expect.")]),e._v(" "),t("p",[e._v("A key part of the solution here is for mobile wallets to have always-online channel counterparties. These counterparties are likely to be Lightning Service Providers (LSPs), which manage channel liquidity and stay online on behalf of end users, but they may be any always-online node.")]),e._v(" "),t("p",[e._v("Enter asynchronous Lightning payments. Async payments utilize always-online channel counterparties on both ends, sender and receiver. The sender’s counterparty will hold onto a payment until it receives an onion message from the recipient's counterparty indicating the recipient is online and ready to receive funds. At this point, the sender’s counterparty releases the payment. Note that the sender's \"counterparty\" may be the sender themselves, if they are always online and sending to an\noften-offline receiver.")]),e._v(" "),t("p",[e._v("While it may sound like it, this does not tie up network liquidity via long CLTV timeouts like today's \"async payments\" because the only locked liquidity is the sender's, and the sender has already bid farewell to those funds.")]),e._v(" "),t("p",[e._v("For more information, "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("follow the development of async payments"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"future-security-directions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#future-security-directions"}},[e._v("#")]),e._v(" Future Security Directions")]),e._v(" "),t("p",[e._v("The concept of onion messages might make you ask: “Free, flexible messages? What if there’s a ton of spam, or people stream videos over Lightning?”")]),e._v(" "),t("p",[e._v("The good news is that there are many ways to rate limit onion messages. For example, limiting peers to a few kilobytes worth of onion messages per second would not be enough bandwidth to allow for streaming. You can also restrict forwarded onion messages to channel peers only, meaning that even if someone attempted a full-on DoS attack, they would be forced to open a great deal of channels.")]),e._v(" "),t("p",[e._v("For more information, see this "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2022-June/003623.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("mailing list post and replies"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"seeya"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#seeya"}},[e._v("#")]),e._v(" Seeya")]),e._v(" "),t("p",[e._v("Thanks for taking the time to learn about onion messages and their use cases. We think it’s a big first step towards a grandparent-friendly noncustodial Lightning UX.")]),e._v(" "),t("p",[e._v("Want to contribute to LDK? Join us on GitHub at our "),t("a",{attrs:{href:"https://github.com/lightningdevkit/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK repo"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{358:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-1.8264e375.png"},359:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-2.e3e05fcb.png"},360:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-3.fd401501.png"},361:function(e,t,n){e.exports=n.p+"assets/img/OM-dm-image-4.934aee81.png"},397:function(e,t,n){"use strict";n.r(t);var o=n(7),s=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("We recently merged support for onion message forwarding, a precursor to deprecating today’s Lightning invoice format, in favor of "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/798",target:"_blank",rel:"noopener noreferrer"}},[e._v("offers"),t("OutboundLink")],1),e._v(". Offers bring many improvements to Lightning, including static invoices, refunds, and receiving payments in a way that doesn’t reveal your node ID or UTXOs. Then, once offer extensions are added, support for subscriptions follows.")]),e._v(" "),t("p",[e._v("So a lot is happening. Including…")]),e._v(" "),t("p",[e._v("Once the network supports "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/ptlc/",target:"_blank",rel:"noopener noreferrer"}},[e._v("PTLCs"),t("OutboundLink")],1),e._v(", onion messages will help enable "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("asynchronous Lightning payments"),t("OutboundLink")],1),e._v(" that remove the rule requiring nodes to be online when receiving payments. We expect onion messages to provide a better foundation for noncustodial Lightning payment UX, including privacy bonuses.")]),e._v(" "),t("h2",{attrs:{id:"how-onion-messages-work"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#how-onion-messages-work"}},[e._v("#")]),e._v(" How Onion Messages Work")]),e._v(" "),t("p",[e._v("Onion messages are lightweight, flexible messages sent between Lightning Network peers using onion routing. Unlike today’s payment messages, peers may send onion messages along a blinded route, thus concealing the recipient’s info. But what’s a blinded route?")]),e._v(" "),t("h2",{attrs:{id:"blinded-routes"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#blinded-routes"}},[e._v("#")]),e._v(" Blinded Routes")]),e._v(" "),t("p",[e._v("If Alice doesn’t want to reveal lots of personal information about her channels and UTXOs, she can use cryptography to create an obfuscated or “blinded” route to herself for the sender (we’ll call him Bob) to send an onion message along. To construct this route, she’ll first find a route to herself from some PopularNode in the graph that has a lot of peers.")]),e._v(" "),t("p",[e._v("By selecting PopularNode from this network chart, Alice’s anonymity set includes all highlighted peers:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(358),alt:"OM"}})]),e._v(" "),t("p",[e._v("To Bob and any other observers, any node within two hops of PopularNode could be the destination of the onion message. Adding more hops further expands Alice’s anonymity set. (Note that PopularNode’s direct peers are candidates because blinded routes may contain fake dummy hops.)")]),e._v(" "),t("p",[e._v("After selecting the path from PopularNode, she’ll create an encrypted blob for each hop that contains information about reaching the next hop, which ends at her node. At this point, the blinded route looks like this:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(359),alt:"OM"}})]),e._v(" "),t("p",[e._v("Finally, she’ll provide this blinded route to Bob, who will find a route to PopularNode and use Alice’s blinded route when constructing the last three hop payloads within the onion packet.")]),e._v(" "),t("h2",{attrs:{id:"onion-message-structure"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#onion-message-structure"}},[e._v("#")]),e._v(" Onion Message Structure")]),e._v(" "),t("p",[e._v("Continuing with this example, let’s say Bob finds this path to Alice’s blinded route:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(360),alt:"OM"}})]),e._v(" "),t("p",[e._v("If Bob sends an invoice request through Alice’s blinded route via onion message, his message would look like this:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(361),alt:"OM"}})]),e._v(" "),t("p",[e._v("So each intermediate layer of the onion contains encrypted forwarding information for the next hop, and the last layer contains the content of the onion message intended for the final hop. This content may include invoice requests and invoices for offers.")]),e._v(" "),t("h2",{attrs:{id:"beyond-offers-asynchronous-payments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#beyond-offers-asynchronous-payments"}},[e._v("#")]),e._v(" Beyond Offers: Asynchronous Payments")]),e._v(" "),t("p",[e._v("While offers were the original point of onion messages, their flexible format unlocks further opportunities to improve the Lightning Network.")]),e._v(" "),t("p",[e._v("For context, a significant problem facing the Lightning Network is that users running noncustodial Lightning wallets on phones must have their wallet app in the foreground to receive payments. This is a big departure from the Cash App-like UX that users want and even expect.")]),e._v(" "),t("p",[e._v("A key part of the solution here is for mobile wallets to have always-online channel counterparties. These counterparties are likely to be Lightning Service Providers (LSPs), which manage channel liquidity and stay online on behalf of end users, but they may be any always-online node.")]),e._v(" "),t("p",[e._v("Enter asynchronous Lightning payments. Async payments utilize always-online channel counterparties on both ends, sender and receiver. The sender’s counterparty will hold onto a payment until it receives an onion message from the recipient's counterparty indicating the recipient is online and ready to receive funds. At this point, the sender’s counterparty releases the payment. Note that the sender's \"counterparty\" may be the sender themselves, if they are always online and sending to an\noften-offline receiver.")]),e._v(" "),t("p",[e._v("While it may sound like it, this does not tie up network liquidity via long CLTV timeouts like today's \"async payments\" because the only locked liquidity is the sender's, and the sender has already bid farewell to those funds.")]),e._v(" "),t("p",[e._v("For more information, "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("follow the development of async payments"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"future-security-directions"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#future-security-directions"}},[e._v("#")]),e._v(" Future Security Directions")]),e._v(" "),t("p",[e._v("The concept of onion messages might make you ask: “Free, flexible messages? What if there’s a ton of spam, or people stream videos over Lightning?”")]),e._v(" "),t("p",[e._v("The good news is that there are many ways to rate limit onion messages. For example, limiting peers to a few kilobytes worth of onion messages per second would not be enough bandwidth to allow for streaming. You can also restrict forwarded onion messages to channel peers only, meaning that even if someone attempted a full-on DoS attack, they would be forced to open a great deal of channels.")]),e._v(" "),t("p",[e._v("For more information, see this "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2022-June/003623.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("mailing list post and replies"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"seeya"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#seeya"}},[e._v("#")]),e._v(" Seeya")]),e._v(" "),t("p",[e._v("Thanks for taking the time to learn about onion messages and their use cases. We think it’s a big first step towards a grandparent-friendly noncustodial Lightning UX.")]),e._v(" "),t("p",[e._v("Want to contribute to LDK? Join us on GitHub at our "),t("a",{attrs:{href:"https://github.com/lightningdevkit/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK repo"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/14.af63b659.js b/assets/js/14.9dbec691.js similarity index 60% rename from assets/js/14.af63b659.js rename to assets/js/14.9dbec691.js index f32a6975a..495710af4 100644 --- a/assets/js/14.af63b659.js +++ b/assets/js/14.9dbec691.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{324:function(t,e,n){},371:function(t,e,n){"use strict";n(324)},441:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:(t,{props:e,slots:n})=>t("span",{class:["badge",e.type],style:{verticalAlign:e.vertical}},e.text||n().default)},p=(n(371),n(7)),l=Object(p.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=l.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{323:function(t,e,n){},369:function(t,e,n){"use strict";n(323)},439:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:(t,{props:e,slots:n})=>t("span",{class:["badge",e.type],style:{verticalAlign:e.vertical}},e.text||n().default)},p=(n(369),n(7)),l=Object(p.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/15.84116d0f.js b/assets/js/15.9b4e9bd8.js similarity index 65% rename from assets/js/15.84116d0f.js rename to assets/js/15.9b4e9bd8.js index 3ffa8662e..999f7218e 100644 --- a/assets/js/15.84116d0f.js +++ b/assets/js/15.9b4e9bd8.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{325:function(t,e,a){},372:function(t,e,a){"use strict";a(325)},384:function(t,e,a){"use strict";a.r(e);var s={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(372),a(7)),n=Object(i.a)(s,(function(){return(0,this._self._c)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{324:function(t,e,a){},370:function(t,e,a){"use strict";a(324)},382:function(t,e,a){"use strict";a.r(e);var s={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(370),a(7)),n=Object(i.a)(s,(function(){return(0,this._self._c)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/16.efc42721.js b/assets/js/16.41c244cb.js similarity index 88% rename from assets/js/16.efc42721.js rename to assets/js/16.41c244cb.js index 04c6c936a..bb92979d2 100644 --- a/assets/js/16.efc42721.js +++ b/assets/js/16.41c244cb.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{326:function(e,t,a){},373:function(e,t,a){"use strict";a(326)},385:function(e,t,a){"use strict";a.r(t);var o={name:"CodeGroup",data:()=>({codeTabs:[],activeCodeTabIndex:-1}),watch:{activeCodeTabIndex(e){this.activateCodeTab(e)}},mounted(){this.loadTabs()},methods:{changeCodeTab(e){this.activeCodeTabIndex=e},loadTabs(){this.codeTabs=(this.$slots.default||[]).filter(e=>Boolean(e.componentOptions)).map((e,t)=>(""===e.componentOptions.propsData.active&&(this.activeCodeTabIndex=t),{title:e.componentOptions.propsData.title,elm:e.elm})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab(e){this.codeTabs.forEach(e=>{e.elm&&e.elm.classList.remove("theme-code-block__active")}),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},s=(a(373),a(7)),c=Object(s.a)(o,(function(){var e=this,t=e._self._c;return t("ClientOnly",[t("div",{staticClass:"theme-code-group"},[t("div",{staticClass:"theme-code-group__nav"},[t("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(a,o){return t("li",{key:a.title,staticClass:"theme-code-group__li"},[t("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(a.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?t("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{325:function(e,t,a){},371:function(e,t,a){"use strict";a(325)},383:function(e,t,a){"use strict";a.r(t);var o={name:"CodeGroup",data:()=>({codeTabs:[],activeCodeTabIndex:-1}),watch:{activeCodeTabIndex(e){this.activateCodeTab(e)}},mounted(){this.loadTabs()},methods:{changeCodeTab(e){this.activeCodeTabIndex=e},loadTabs(){this.codeTabs=(this.$slots.default||[]).filter(e=>Boolean(e.componentOptions)).map((e,t)=>(""===e.componentOptions.propsData.active&&(this.activeCodeTabIndex=t),{title:e.componentOptions.propsData.title,elm:e.elm})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab(e){this.codeTabs.forEach(e=>{e.elm&&e.elm.classList.remove("theme-code-block__active")}),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},s=(a(371),a(7)),c=Object(s.a)(o,(function(){var e=this,t=e._self._c;return t("ClientOnly",[t("div",{staticClass:"theme-code-group"},[t("div",{staticClass:"theme-code-group__nav"},[t("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(a,o){return t("li",{key:a.title,staticClass:"theme-code-group__li"},[t("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(a.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?t("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/17.97d938f3.js b/assets/js/17.7d96727c.js similarity index 94% rename from assets/js/17.97d938f3.js rename to assets/js/17.7d96727c.js index 71d1c6106..ff2b87a89 100644 --- a/assets/js/17.97d938f3.js +++ b/assets/js/17.7d96727c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{355:function(e,t,n){e.exports=n.p+"assets/img/phantom-hints.64e934b6.png"},356:function(e,t,n){e.exports=n.p+"assets/img/phantom-pmt.8d872436.png"},394:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Introducing phantom node payments, a new-ish feature for LDK.")]),e._v(" "),t("p",[e._v("Phantom node payments let enterprise users running high-volume lightning nodes generate invoices that can be paid to one of multiple production nodes. Since it’s safe to assume that payers will retry along an alternate route hint if one fails, phantom payments allow for load balancing between nodes and resilience if a node or nodes go down.")]),e._v(" "),t("h2",{attrs:{id:"phantom-payment-flow"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#phantom-payment-flow"}},[e._v("#")]),e._v(" Phantom Payment Flow")]),e._v(" "),t("p",[e._v("Using LNMerchant as an example company, here’s how phantom payments work:")]),e._v(" "),t("ol",[t("li",[t("p",[e._v("Buyer on the Lightning Network requests an invoice")])]),e._v(" "),t("li",[t("p",[e._v("LNMerchant replies with an invoice. Per standard invoice protocol, it contains information on routing to LNMerchant. However, unlike conventional invoice route hints, phantom route hints include a combination of real and fake routing information. This fake or “phantom” routing information will later signal to LDK that the payment’s intended destination is a phantom node.")])])]),e._v(" "),t("p",[e._v("The following illustration demonstrates how phantom route hints work:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(355),alt:"Phantom Hints"}})]),e._v(" "),t("ol",{attrs:{start:"3"}},[t("li",[e._v("The buyer’s node generates a normal route. Using the route hints, the last two hops are [LNMerchantNode, PhantomNode], i.e., the phantom node is the destination node, and the second-to-last hop is an actual LNMerchant node. (Note: If the LNMerchant has public channels, only the last hop containing the fake channel is strictly necessary for the route hints.)")])]),e._v(" "),t("p",[e._v("The buyer uses this route, including the fake forwarding information from the route hints, to generate the payment onion. On Lightning, each hop along the route unwraps one layer of sender-constructed onion.")]),e._v(" "),t("ol",{attrs:{start:"4"}},[t("li",[t("p",[e._v("The buyer forwards the payment to the route’s first hop, which gets forwarded through intermediate hops.")])]),e._v(" "),t("li",[t("p",[e._v("The payment forwards to the second-to-last hop, an actual LNMerchant node.")])]),e._v(" "),t("li",[t("p",[e._v("The LNMerchant node checks what channel to forward the payment to and recognizes a phantom channel ID.")])]),e._v(" "),t("li",[t("p",[e._v("The LNMerchant node knows the phantom node’s secret key, so it can unwrap the last layer of the onion and verify the payment details. It also knows the preimage for the payment, so it can claim the amount owed without forwarding the payment to the non-existent phantom.")])])]),e._v(" "),t("figure",[t("img",{attrs:{src:n(356),alt:"Phantom PMT"}})]),e._v(" "),t("h2",{attrs:{id:"why-it-s-ok-to-not-support-mpp"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-it-s-ok-to-not-support-mpp"}},[e._v("#")]),e._v(" Why It’s OK to Not Support MPP")]),e._v(" "),t("p",[e._v("One potential drawback to phantom node payments is the lack of multi-path payments (MPP) support.")]),e._v(" "),t("p",[e._v("MPP payments benefit large transactions because they aren’t restricted to routes where each channel must carry its entire payment balance.")]),e._v(" "),t("p",[e._v("With this in mind, a compelling compromise is to:")]),e._v(" "),t("ul",[t("li",[e._v("Create MPP-supporting invoices against a single node for large payments.")]),e._v(" "),t("li",[e._v("Create phantom invoices for smaller payments, which are the most common and are unlikely to use MPP.")])]),e._v(" "),t("h2",{attrs:{id:"why-mpp-shouldn-t-be-enabled"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-mpp-shouldn-t-be-enabled"}},[e._v("#")]),e._v(" Why MPP Shouldn’t Be Enabled")]),e._v(" "),t("p",[e._v("Let’s say that we want to implement MPP for phantom payments. In this case, each real LNMerchant node may receive a slice of the phantom node-destined phantom payment. In this case, the question becomes: How do real nodes know when a payment is accepted across all nodes so that it’s safe to release the preimage?")]),e._v(" "),t("p",[e._v("On the surface, it seems like users should be able to tell LDK when a payment has been received across all nodes and is safe to claim. However, this would significantly compromise our safety guarantees because releasing the preimage before receiving the total payment value opens up the possibility for intermediate nodes to claim remaining payment parts. Moreover, implementing this would introduce perilous race conditions, because users would need to “lock” internal LDK data structures to ensure payment claims are atomic. Failing to properly handle these delicate cases would lead to force-closed channels and possibly lost funds.")]),e._v(" "),t("hr"),e._v(" "),t("p",[e._v("Thanks for taking the time to learn about phantom nodes and payments. We think it’s an exciting showcase for the lightning protocol’s flexibility and variety of use cases.")]),e._v(" "),t("p",[e._v("Want to make your own contribution to LDK? Join us on GitHub at our "),t("a",{attrs:{href:"https://github.com/lightningdevkit/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK repo"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{352:function(e,t,n){e.exports=n.p+"assets/img/phantom-hints.64e934b6.png"},353:function(e,t,n){e.exports=n.p+"assets/img/phantom-pmt.8d872436.png"},390:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Introducing phantom node payments, a new-ish feature for LDK.")]),e._v(" "),t("p",[e._v("Phantom node payments let enterprise users running high-volume lightning nodes generate invoices that can be paid to one of multiple production nodes. Since it’s safe to assume that payers will retry along an alternate route hint if one fails, phantom payments allow for load balancing between nodes and resilience if a node or nodes go down.")]),e._v(" "),t("h2",{attrs:{id:"phantom-payment-flow"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#phantom-payment-flow"}},[e._v("#")]),e._v(" Phantom Payment Flow")]),e._v(" "),t("p",[e._v("Using LNMerchant as an example company, here’s how phantom payments work:")]),e._v(" "),t("ol",[t("li",[t("p",[e._v("Buyer on the Lightning Network requests an invoice")])]),e._v(" "),t("li",[t("p",[e._v("LNMerchant replies with an invoice. Per standard invoice protocol, it contains information on routing to LNMerchant. However, unlike conventional invoice route hints, phantom route hints include a combination of real and fake routing information. This fake or “phantom” routing information will later signal to LDK that the payment’s intended destination is a phantom node.")])])]),e._v(" "),t("p",[e._v("The following illustration demonstrates how phantom route hints work:")]),e._v(" "),t("figure",[t("img",{attrs:{src:n(352),alt:"Phantom Hints"}})]),e._v(" "),t("ol",{attrs:{start:"3"}},[t("li",[e._v("The buyer’s node generates a normal route. Using the route hints, the last two hops are [LNMerchantNode, PhantomNode], i.e., the phantom node is the destination node, and the second-to-last hop is an actual LNMerchant node. (Note: If the LNMerchant has public channels, only the last hop containing the fake channel is strictly necessary for the route hints.)")])]),e._v(" "),t("p",[e._v("The buyer uses this route, including the fake forwarding information from the route hints, to generate the payment onion. On Lightning, each hop along the route unwraps one layer of sender-constructed onion.")]),e._v(" "),t("ol",{attrs:{start:"4"}},[t("li",[t("p",[e._v("The buyer forwards the payment to the route’s first hop, which gets forwarded through intermediate hops.")])]),e._v(" "),t("li",[t("p",[e._v("The payment forwards to the second-to-last hop, an actual LNMerchant node.")])]),e._v(" "),t("li",[t("p",[e._v("The LNMerchant node checks what channel to forward the payment to and recognizes a phantom channel ID.")])]),e._v(" "),t("li",[t("p",[e._v("The LNMerchant node knows the phantom node’s secret key, so it can unwrap the last layer of the onion and verify the payment details. It also knows the preimage for the payment, so it can claim the amount owed without forwarding the payment to the non-existent phantom.")])])]),e._v(" "),t("figure",[t("img",{attrs:{src:n(353),alt:"Phantom PMT"}})]),e._v(" "),t("h2",{attrs:{id:"why-it-s-ok-to-not-support-mpp"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-it-s-ok-to-not-support-mpp"}},[e._v("#")]),e._v(" Why It’s OK to Not Support MPP")]),e._v(" "),t("p",[e._v("One potential drawback to phantom node payments is the lack of multi-path payments (MPP) support.")]),e._v(" "),t("p",[e._v("MPP payments benefit large transactions because they aren’t restricted to routes where each channel must carry its entire payment balance.")]),e._v(" "),t("p",[e._v("With this in mind, a compelling compromise is to:")]),e._v(" "),t("ul",[t("li",[e._v("Create MPP-supporting invoices against a single node for large payments.")]),e._v(" "),t("li",[e._v("Create phantom invoices for smaller payments, which are the most common and are unlikely to use MPP.")])]),e._v(" "),t("h2",{attrs:{id:"why-mpp-shouldn-t-be-enabled"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-mpp-shouldn-t-be-enabled"}},[e._v("#")]),e._v(" Why MPP Shouldn’t Be Enabled")]),e._v(" "),t("p",[e._v("Let’s say that we want to implement MPP for phantom payments. In this case, each real LNMerchant node may receive a slice of the phantom node-destined phantom payment. In this case, the question becomes: How do real nodes know when a payment is accepted across all nodes so that it’s safe to release the preimage?")]),e._v(" "),t("p",[e._v("On the surface, it seems like users should be able to tell LDK when a payment has been received across all nodes and is safe to claim. However, this would significantly compromise our safety guarantees because releasing the preimage before receiving the total payment value opens up the possibility for intermediate nodes to claim remaining payment parts. Moreover, implementing this would introduce perilous race conditions, because users would need to “lock” internal LDK data structures to ensure payment claims are atomic. Failing to properly handle these delicate cases would lead to force-closed channels and possibly lost funds.")]),e._v(" "),t("hr"),e._v(" "),t("p",[e._v("Thanks for taking the time to learn about phantom nodes and payments. We think it’s an exciting showcase for the lightning protocol’s flexibility and variety of use cases.")]),e._v(" "),t("p",[e._v("Want to make your own contribution to LDK? Join us on GitHub at our "),t("a",{attrs:{href:"https://github.com/lightningdevkit/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK repo"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/18.ef2e85d6.js b/assets/js/18.06dcfb51.js similarity index 92% rename from assets/js/18.ef2e85d6.js rename to assets/js/18.06dcfb51.js index 14c2e8c82..deb453f59 100644 --- a/assets/js/18.ef2e85d6.js +++ b/assets/js/18.06dcfb51.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{251:function(t,a){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},381:function(t,a,e){"use strict";e.r(a);var s=e(259),n=e(251),i={name:"FrontmatterKey",components:{LayoutWrap:s.a},computed:{items(){return this.$frontmatterKey.list}},methods:{displayName(t){return this.$page.path.startsWith("/blog/tags/")?Object(n.capitalize)(t):t}}},r=e(7),o=Object(r.a)(i,(function(){var t=this,a=t._self._c;return a("LayoutWrap",[a("main",{staticClass:"page"},[a("div",{staticClass:"theme-default-content"},[this.$page.path.startsWith("/blog/tags/")?a("h1",[t._v("Tags")]):a("h1",[t._v("Authors")]),t._v(" "),a("ul",t._l(t.items,(function(e){return a("li",{key:e.name},[a("router-link",{attrs:{to:e.path}},[t._v(t._s(t.displayName(e.name)))])],1)})),0)])])])}),[],!1,null,null,null);a.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{251:function(t,a){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},379:function(t,a,e){"use strict";e.r(a);var s=e(259),n=e(251),i={name:"FrontmatterKey",components:{LayoutWrap:s.a},computed:{items(){return this.$frontmatterKey.list}},methods:{displayName(t){return this.$page.path.startsWith("/blog/tags/")?Object(n.capitalize)(t):t}}},r=e(7),o=Object(r.a)(i,(function(){var t=this,a=t._self._c;return a("LayoutWrap",[a("main",{staticClass:"page"},[a("div",{staticClass:"theme-default-content"},[this.$page.path.startsWith("/blog/tags/")?a("h1",[t._v("Tags")]):a("h1",[t._v("Authors")]),t._v(" "),a("ul",t._l(t.items,(function(e){return a("li",{key:e.name},[a("router-link",{attrs:{to:e.path}},[t._v(t._s(t.displayName(e.name)))])],1)})),0)])])])}),[],!1,null,null,null);a.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/19.b2d16c8c.js b/assets/js/19.eefbf0b9.js similarity index 95% rename from assets/js/19.b2d16c8c.js rename to assets/js/19.eefbf0b9.js index 61c7d6ef9..2e319857a 100644 --- a/assets/js/19.b2d16c8c.js +++ b/assets/js/19.eefbf0b9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{348:function(e,t,a){e.exports=a.p+"assets/img/alby-architecture.73d58301.png"},387:function(e,t,a){"use strict";a.r(t);var n=a(7),i=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Alby Hub"),t("OutboundLink")],1),e._v(" is a self-custodial Lightning wallet that combines ease of use, ownership, and seamless connectivity to apps. It serves as a central hub for managing bitcoin payments, featuring a simple plug-in mechanism that links the integrated Lightning node with apps across platforms and operating systems.\nThis setup allows users to control Alby Hub from mobile wallets, browser extensions, and directly within social media apps, games, and more—eliminating the need to deposit funds into apps or spread your Bitcoin balance across multiple accounts.")]),e._v(" "),t("p",[e._v("Alby Hub manages to improve ease of use of a self-custodial lightning wallet while giving users full control over their wallet and payment channels if desired, thus providing "),t("a",{attrs:{href:"https://blog.getalby.com/what-is-alby-hub/",target:"_blank",rel:"noopener noreferrer"}},[e._v("lightning sovereignty for everyone"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("Alby Hub is a versatile application built with Go for the backend and React for the frontend. It integrates the Rust-based LDK Node implementation with custom UniFFI bindings.")]),e._v(" "),t("p",[e._v("Blockchain data is sourced from Esplora servers to minimize sync times and disk usage.")]),e._v(" "),t("p",[e._v("A SQLite database is used for storing transaction metadata, providing detailed context around each transaction.")]),e._v(" "),t("p",[e._v("The application supports two modes: - Wails (Desktop app): Compatible with Mac, Windows, and Linux. - HTTP (Web app): Deployable via Docker or run directly as a Linux binary.")]),e._v(" "),t("p",[e._v("Alby Hub also integrates with Lightning Service Providers (LSPs) through an API, enabling users to choose from a list of LSPs and purchase payment channels in two clicks to source inbound liquidity. With the help of the LSP API channel management will be automated and further abstracted away.")]),e._v(" "),t("p",[e._v("The integrated "),t("a",{attrs:{href:"https://nwc.dev/",target:"_blank",rel:"noopener noreferrer"}},[e._v("NWC"),t("OutboundLink")],1),e._v(" wallet service is what makes Alby Hub a new kind of a self-custodial lightning wallet. NWC allows direct connections to "),t("a",{attrs:{href:"https://github.com/getAlby/awesome-nwc",target:"_blank",rel:"noopener noreferrer"}},[e._v("third-party apps"),t("OutboundLink")],1),e._v(", greatly extending the app's functionality. This means users can plug in their Hub by copying a connection string into other apps instead of depositing funds before using an app.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(348),alt:"Alby architecture"}})]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("Integrating LDK directly into Alby Hub, rather than relying on an external daemon, simplifies deployment and operation. This integration is what made building Alby Hub feasible. Its resource efficiency gives users the flexibility to choose "),t("a",{attrs:{href:"https://blog.getalby.com/run-alby-hub-on-servers-desktops-and-microcomputers/",target:"_blank",rel:"noopener noreferrer"}},[e._v("where to run Alby Hub"),t("OutboundLink")],1),e._v("—whether on servers, desktops, or microcomputers.")]),e._v(" "),t("p",[e._v("Another crucial factor was payment processing time. Alby is your companion for bitcoin payments wherever you go whether at a POS or directly within apps. Fast payment processing is crucial for delivering a seamless user experience in third-party apps.")]),e._v(" "),t("p",[e._v("LDK Node offers a well-structured and designed public API, making integration fast and development straightforward. When needed, the Spiral team provided consistent support throughout the integration process and continues to do so in the operation of Alby Hub. This collaboration has been crucial to delivering a sophisticated product.")]),e._v(" "),t("p",[e._v("As a consequence, Alby Hub lowers the cost barrier for running a lightning node, making self-custodial lightning payments accessible to those with limited budgets and without technical skills.")])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{355:function(e,t,a){e.exports=a.p+"assets/img/alby-architecture.73d58301.png"},392:function(e,t,a){"use strict";a.r(t);var n=a(7),i=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Alby Hub"),t("OutboundLink")],1),e._v(" is a self-custodial Lightning wallet that combines ease of use, ownership, and seamless connectivity to apps. It serves as a central hub for managing bitcoin payments, featuring a simple plug-in mechanism that links the integrated Lightning node with apps across platforms and operating systems.\nThis setup allows users to control Alby Hub from mobile wallets, browser extensions, and directly within social media apps, games, and more—eliminating the need to deposit funds into apps or spread your Bitcoin balance across multiple accounts.")]),e._v(" "),t("p",[e._v("Alby Hub manages to improve ease of use of a self-custodial lightning wallet while giving users full control over their wallet and payment channels if desired, thus providing "),t("a",{attrs:{href:"https://blog.getalby.com/what-is-alby-hub/",target:"_blank",rel:"noopener noreferrer"}},[e._v("lightning sovereignty for everyone"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("Alby Hub is a versatile application built with Go for the backend and React for the frontend. It integrates the Rust-based LDK Node implementation with custom UniFFI bindings.")]),e._v(" "),t("p",[e._v("Blockchain data is sourced from Esplora servers to minimize sync times and disk usage.")]),e._v(" "),t("p",[e._v("A SQLite database is used for storing transaction metadata, providing detailed context around each transaction.")]),e._v(" "),t("p",[e._v("The application supports two modes: - Wails (Desktop app): Compatible with Mac, Windows, and Linux. - HTTP (Web app): Deployable via Docker or run directly as a Linux binary.")]),e._v(" "),t("p",[e._v("Alby Hub also integrates with Lightning Service Providers (LSPs) through an API, enabling users to choose from a list of LSPs and purchase payment channels in two clicks to source inbound liquidity. With the help of the LSP API channel management will be automated and further abstracted away.")]),e._v(" "),t("p",[e._v("The integrated "),t("a",{attrs:{href:"https://nwc.dev/",target:"_blank",rel:"noopener noreferrer"}},[e._v("NWC"),t("OutboundLink")],1),e._v(" wallet service is what makes Alby Hub a new kind of a self-custodial lightning wallet. NWC allows direct connections to "),t("a",{attrs:{href:"https://github.com/getAlby/awesome-nwc",target:"_blank",rel:"noopener noreferrer"}},[e._v("third-party apps"),t("OutboundLink")],1),e._v(", greatly extending the app's functionality. This means users can plug in their Hub by copying a connection string into other apps instead of depositing funds before using an app.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(355),alt:"Alby architecture"}})]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("Integrating LDK directly into Alby Hub, rather than relying on an external daemon, simplifies deployment and operation. This integration is what made building Alby Hub feasible. Its resource efficiency gives users the flexibility to choose "),t("a",{attrs:{href:"https://blog.getalby.com/run-alby-hub-on-servers-desktops-and-microcomputers/",target:"_blank",rel:"noopener noreferrer"}},[e._v("where to run Alby Hub"),t("OutboundLink")],1),e._v("—whether on servers, desktops, or microcomputers.")]),e._v(" "),t("p",[e._v("Another crucial factor was payment processing time. Alby is your companion for bitcoin payments wherever you go whether at a POS or directly within apps. Fast payment processing is crucial for delivering a seamless user experience in third-party apps.")]),e._v(" "),t("p",[e._v("LDK Node offers a well-structured and designed public API, making integration fast and development straightforward. When needed, the Spiral team provided consistent support throughout the integration process and continues to do so in the operation of Alby Hub. This collaboration has been crucial to delivering a sophisticated product.")]),e._v(" "),t("p",[e._v("As a consequence, Alby Hub lowers the cost barrier for running a lightning node, making self-custodial lightning payments accessible to those with limited budgets and without technical skills.")])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/20.b0d6e9b4.js b/assets/js/20.963f0e81.js similarity index 97% rename from assets/js/20.b0d6e9b4.js rename to assets/js/20.963f0e81.js index 7521a0dca..954ab098e 100644 --- a/assets/js/20.b0d6e9b4.js +++ b/assets/js/20.963f0e81.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{349:function(e,t,i){e.exports=i.p+"assets/img/bitkit-architecture.c0e1d507.png"},391:function(e,t,i){"use strict";i.r(t);var n=i(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("In 2020, the Lightning Network was in its early stages, and most people used custodial wallets. We believe this trend towards custodial wallets contradicts the Bitcoin ethos, so we decided to create a self-custodial alternative that offers a great user experience for all, not just technical users.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank",rel:"noopener noreferrer"}},[e._v("And that's how Bitkit was born."),t("OutboundLink")],1)]),e._v(" "),t("h1",{attrs:{id:"before-ldk"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#before-ldk"}},[e._v("#")]),e._v(" Before LDK")]),e._v(" "),t("p",[e._v("Choosing your tech stack is always challenging. When we first looked into the available Lightning Network implementations, we faced a difficult decision.")]),e._v(" "),t("p",[e._v("Rust-lightning, now known as LDK, had a promising modular architecture but was still in the early stages of development. We considered developing an implementation from scratch to meet Bitkit's specific needs, akin to Acinq's approach with Eclair, but other priorities led us to set this option aside. Ultimately, we adopted LND, the most prevalent implementation at the time. Breez had successfully showcased its potential, making it a logical choice for our stack.")]),e._v(" "),t("p",[e._v("We used LND as the backbone of Bitkit for more than a year, but one aspect stood in the way of providing an optimal user experience: the initialization time. LND utilizes Neutrino, a light Bitcoin client that downloads compact block filters to synchronize with the blockchain. Although it provides better privacy than Electrum Server or Esplora, it's not as fast.")]),e._v(" "),t("p",[e._v("The implications of the initial synchronization time extended well beyond waiting a few seconds. The longer the app stays closed, the longer the synchronization time. We often impatiently closed the app before it finished syncing, causing it to stay out of sync permanently. When we waited for it to fully synchronize, we often found our channel closed, forcing us to start over.")]),e._v(" "),t("p",[e._v("If we were frustrated, Bitkit users would be, too. This reminded us of the second-order effects caused by the technology stacked into our products. John, our CEO, said, “We can’t do this to our users.”")]),e._v(" "),t("p",[e._v("LND was not designed to be modular, making it challenging to swap out Neutrino. To provide the user experience we wanted, we'd need to develop Bitkit on top of a more flexible library. Otherwise, the user experience of self-custodial wallets would continue to fall short, and custodial wallets would remain more popular.")]),e._v(" "),t("p",[e._v("Meanwhile, LDK had come a long way since the early Rust-Lightning days. After revisiting it, its mobile-friendliness convinced us it was the right path forward. The switching cost was high, but we believed our decision would pay off in the long run. So we archived our "),t("a",{attrs:{href:"https://github.com/synonymdev/react-native-lightning",target:"_blank",rel:"noopener noreferrer"}},[e._v("React Native Lightning library"),t("OutboundLink")],1),e._v(" and merged a "),t("a",{attrs:{href:"https://github.com/synonymdev/bitkit/pull/146",target:"_blank",rel:"noopener noreferrer"}},[e._v("pull request"),t("OutboundLink")],1),e._v(", subtracting more than a year of work.")]),e._v(" "),t("p",[e._v("It was time for LDK.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("Bitkit is built on React Native, and LDK primarily supports Kotlin and Swift bindings. Not to mention, there wasn't an off-the-shelf "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/announcing-ldk-node/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node"),t("OutboundLink")],1),e._v(" available back then. This led us to develop the "),t("a",{attrs:{href:"https://github.com/synonymdev/react-native-ldk",target:"_blank",rel:"noopener noreferrer"}},[e._v("React Native LDK library"),t("OutboundLink")],1),e._v(" from the ground up, which has since been adopted by "),t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Etta"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://github.com/bennyhodl/baywallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Bay"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("By the time we decided to implement LDK, we had already built an on-chain wallet into Bitkit. LDK's flexibility allowed us to preserve it while we focused on rebuilding the Lightning logic.")]),e._v(" "),t("p",[e._v("We've recently "),t("a",{attrs:{href:"https://github.com/synonymdev/bitkit/pull/1450",target:"_blank",rel:"noopener noreferrer"}},[e._v("refactored the on-chain logic out of Bitkit"),t("OutboundLink")],1),e._v(" into a library, and LDK once again made it easy to retain the required methods and pass them through as needed.")]),e._v(" "),t("p",[e._v("We've also developed a custom "),t("a",{attrs:{href:"https://lightningdevkit.org/key_management/",target:"_blank",rel:"noopener noreferrer"}},[e._v("key manager"),t("OutboundLink")],1),e._v(" so the outputs of channel closure transactions get spent directly to Bitkit's on-chain wallet, removing the need for a costly sweeping transaction.")]),e._v(" "),t("p",[e._v("Throughout both on-chain wallet migrations, LDK enabled us to use Electrum Servers as the source of blockchain data, significantly reducing the initial sync time we've previously encountered.")]),e._v(" "),t("p",[e._v("To further minimize initialization delays, we started using LDK's "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/announcing-rapid-gossip-sync/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rapid Gossip Sync"),t("OutboundLink")],1),e._v(". It skips client-side signature verification and compresses graph data, shrinking the required bandwidth and CPU resources. Without RGS, the easiest alternative to achieve fast initialization would be delegating routing to our servers, revealing users' payment destinations. With RGS, pathfinding is fast and client-side, preserving Lightning's privacy properties.")]),e._v(" "),t("p",[e._v("The customizability of the "),t("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/struct.ProbabilisticScorer.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("probabilistic scorer"),t("OutboundLink")],1),e._v(" parameters allowed us to further improve route-finding, translating into a higher payment success rate for users.")]),e._v(" "),t("p",[e._v("In addition, we've architected a custom backup server to meet Bitkit's specific requirements, which LDK was flexible enough to accommodate.")]),e._v(" "),t("figure",[t("img",{attrs:{src:i(349),alt:"Bitkit architecture"}})]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("Migrating to LDK wasn't an easy decision, but time has proven it to be the correct one. The support from the Spiral team was instrumental in easing the migration.")]),e._v(" "),t("p",[e._v("LDK enables us to focus on building a great wallet instead of getting bogged down by the complexities of the Lightning Network protocol.")]),e._v(" "),t("p",[e._v("Ultimately, LDK helps us to narrow the user experience gap between custodial and self-custodial wallets. As long as the lack of options leads people to rely on custodians, LDK will be pivotal in helping us to build a better alternative.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{347:function(e,t,i){e.exports=i.p+"assets/img/bitkit-architecture.c0e1d507.png"},387:function(e,t,i){"use strict";i.r(t);var n=i(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("In 2020, the Lightning Network was in its early stages, and most people used custodial wallets. We believe this trend towards custodial wallets contradicts the Bitcoin ethos, so we decided to create a self-custodial alternative that offers a great user experience for all, not just technical users.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank",rel:"noopener noreferrer"}},[e._v("And that's how Bitkit was born."),t("OutboundLink")],1)]),e._v(" "),t("h1",{attrs:{id:"before-ldk"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#before-ldk"}},[e._v("#")]),e._v(" Before LDK")]),e._v(" "),t("p",[e._v("Choosing your tech stack is always challenging. When we first looked into the available Lightning Network implementations, we faced a difficult decision.")]),e._v(" "),t("p",[e._v("Rust-lightning, now known as LDK, had a promising modular architecture but was still in the early stages of development. We considered developing an implementation from scratch to meet Bitkit's specific needs, akin to Acinq's approach with Eclair, but other priorities led us to set this option aside. Ultimately, we adopted LND, the most prevalent implementation at the time. Breez had successfully showcased its potential, making it a logical choice for our stack.")]),e._v(" "),t("p",[e._v("We used LND as the backbone of Bitkit for more than a year, but one aspect stood in the way of providing an optimal user experience: the initialization time. LND utilizes Neutrino, a light Bitcoin client that downloads compact block filters to synchronize with the blockchain. Although it provides better privacy than Electrum Server or Esplora, it's not as fast.")]),e._v(" "),t("p",[e._v("The implications of the initial synchronization time extended well beyond waiting a few seconds. The longer the app stays closed, the longer the synchronization time. We often impatiently closed the app before it finished syncing, causing it to stay out of sync permanently. When we waited for it to fully synchronize, we often found our channel closed, forcing us to start over.")]),e._v(" "),t("p",[e._v("If we were frustrated, Bitkit users would be, too. This reminded us of the second-order effects caused by the technology stacked into our products. John, our CEO, said, “We can’t do this to our users.”")]),e._v(" "),t("p",[e._v("LND was not designed to be modular, making it challenging to swap out Neutrino. To provide the user experience we wanted, we'd need to develop Bitkit on top of a more flexible library. Otherwise, the user experience of self-custodial wallets would continue to fall short, and custodial wallets would remain more popular.")]),e._v(" "),t("p",[e._v("Meanwhile, LDK had come a long way since the early Rust-Lightning days. After revisiting it, its mobile-friendliness convinced us it was the right path forward. The switching cost was high, but we believed our decision would pay off in the long run. So we archived our "),t("a",{attrs:{href:"https://github.com/synonymdev/react-native-lightning",target:"_blank",rel:"noopener noreferrer"}},[e._v("React Native Lightning library"),t("OutboundLink")],1),e._v(" and merged a "),t("a",{attrs:{href:"https://github.com/synonymdev/bitkit/pull/146",target:"_blank",rel:"noopener noreferrer"}},[e._v("pull request"),t("OutboundLink")],1),e._v(", subtracting more than a year of work.")]),e._v(" "),t("p",[e._v("It was time for LDK.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("Bitkit is built on React Native, and LDK primarily supports Kotlin and Swift bindings. Not to mention, there wasn't an off-the-shelf "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/announcing-ldk-node/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node"),t("OutboundLink")],1),e._v(" available back then. This led us to develop the "),t("a",{attrs:{href:"https://github.com/synonymdev/react-native-ldk",target:"_blank",rel:"noopener noreferrer"}},[e._v("React Native LDK library"),t("OutboundLink")],1),e._v(" from the ground up, which has since been adopted by "),t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Etta"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://github.com/bennyhodl/baywallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Bay"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("By the time we decided to implement LDK, we had already built an on-chain wallet into Bitkit. LDK's flexibility allowed us to preserve it while we focused on rebuilding the Lightning logic.")]),e._v(" "),t("p",[e._v("We've recently "),t("a",{attrs:{href:"https://github.com/synonymdev/bitkit/pull/1450",target:"_blank",rel:"noopener noreferrer"}},[e._v("refactored the on-chain logic out of Bitkit"),t("OutboundLink")],1),e._v(" into a library, and LDK once again made it easy to retain the required methods and pass them through as needed.")]),e._v(" "),t("p",[e._v("We've also developed a custom "),t("a",{attrs:{href:"https://lightningdevkit.org/key_management/",target:"_blank",rel:"noopener noreferrer"}},[e._v("key manager"),t("OutboundLink")],1),e._v(" so the outputs of channel closure transactions get spent directly to Bitkit's on-chain wallet, removing the need for a costly sweeping transaction.")]),e._v(" "),t("p",[e._v("Throughout both on-chain wallet migrations, LDK enabled us to use Electrum Servers as the source of blockchain data, significantly reducing the initial sync time we've previously encountered.")]),e._v(" "),t("p",[e._v("To further minimize initialization delays, we started using LDK's "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/announcing-rapid-gossip-sync/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rapid Gossip Sync"),t("OutboundLink")],1),e._v(". It skips client-side signature verification and compresses graph data, shrinking the required bandwidth and CPU resources. Without RGS, the easiest alternative to achieve fast initialization would be delegating routing to our servers, revealing users' payment destinations. With RGS, pathfinding is fast and client-side, preserving Lightning's privacy properties.")]),e._v(" "),t("p",[e._v("The customizability of the "),t("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/struct.ProbabilisticScorer.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("probabilistic scorer"),t("OutboundLink")],1),e._v(" parameters allowed us to further improve route-finding, translating into a higher payment success rate for users.")]),e._v(" "),t("p",[e._v("In addition, we've architected a custom backup server to meet Bitkit's specific requirements, which LDK was flexible enough to accommodate.")]),e._v(" "),t("figure",[t("img",{attrs:{src:i(347),alt:"Bitkit architecture"}})]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("Migrating to LDK wasn't an easy decision, but time has proven it to be the correct one. The support from the Spiral team was instrumental in easing the migration.")]),e._v(" "),t("p",[e._v("LDK enables us to focus on building a great wallet instead of getting bogged down by the complexities of the Lightning Network protocol.")]),e._v(" "),t("p",[e._v("Ultimately, LDK helps us to narrow the user experience gap between custodial and self-custodial wallets. As long as the lack of options leads people to rely on custodians, LDK will be pivotal in helping us to build a better alternative.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/21.7fcbe2f6.js b/assets/js/21.baa425a1.js similarity index 98% rename from assets/js/21.7fcbe2f6.js rename to assets/js/21.baa425a1.js index 14fc4d9d3..2e4a5f79e 100644 --- a/assets/js/21.7fcbe2f6.js +++ b/assets/js/21.baa425a1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{354:function(e,t,a){e.exports=a.p+"assets/img/cash-app-architecture.b24c7ec1.svg"},393:function(e,t,a){"use strict";a.r(t);var n=a(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Cash App allows users to instantly deposit and withdraw bitcoin over the lightning network. As an engineer on the Cash App Lightning Wallet team, I was very involved in the entire implementation process.")]),e._v(" "),t("p",[e._v("Cash App is the #1 Finance App in the app store – we have extremely high standards for product development and the infrastructure that powers all our cool features. We were looking for a solution that would ensure high reliability, high scalability, and a stellar developer experience. Cash App is the financial hub for millions of people and often the first place an individual acquires bitcoin. It’s important to have a slick user experience and robust infrastructure that can onboard many new users. As a publicly traded company we take security seriously and need the ability to customize our wallet implementation in order to adhere to strict standards.")]),e._v(" "),t("p",[e._v("We chose LDK for various reasons over other implementations. It provided us with a lot of customizability and flexibility. The "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java bindings"),t("OutboundLink")],1),e._v(" let us develop in Kotlin, which is the preferred language for backend services. We also have a great working relationship with the "),t("a",{attrs:{href:"https://spiral.xyz/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spiral"),t("OutboundLink")],1),e._v(" folks, making it easy to collaborate on more advanced feature requests such as phantom invoices.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("LDK allowed us to develop a scalable lightning node infrastructure. Cash App runs multiple wallet nodes and has strict parameters around opening channels and connecting to peers. We have logic that does advanced probing in the background in order to ensure an up-to-date snapshot of liquidity on the lightning network.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(354),alt:"CashApp architecture"}})]),e._v(" "),t("p",[e._v("Probing is done before every send, allowing us to pre-fetch a route and execute the send once the customer confirms. LDK’s "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/introducing-phantom-node-payments/",target:"_blank",rel:"noopener noreferrer"}},[e._v("phantom node"),t("OutboundLink")],1),e._v(" feature makes it possible to generate invoices that can be claimed by more than one node. We use MySQL to save our channel state data + node metadata in order to quickly shut down and start up nodes at will on different servers. Additionally, LDK lets us run AB tests on different pathfinding algorithms.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("LDK made it possible to relatively quickly build an easy-to-use lightning wallet while adhering to the complicated constraints Cash App faces as a publicly traded company with tens of millions of users. Users can now instantly deposit and withdraw bitcoin to Cash App over lightning.")]),e._v(" "),t("p",[e._v("To learn more check out this "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=kbhL5RqL8Aw",target:"_blank",rel:"noopener noreferrer"}},[e._v("presentation"),t("OutboundLink")],1),e._v(" at btc++ explaining some of the trade-offs the Cash App team had to think about when comparing LDK to other solutions.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{354:function(e,t,a){e.exports=a.p+"assets/img/cash-app-architecture.b24c7ec1.svg"},391:function(e,t,a){"use strict";a.r(t);var n=a(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Cash App allows users to instantly deposit and withdraw bitcoin over the lightning network. As an engineer on the Cash App Lightning Wallet team, I was very involved in the entire implementation process.")]),e._v(" "),t("p",[e._v("Cash App is the #1 Finance App in the app store – we have extremely high standards for product development and the infrastructure that powers all our cool features. We were looking for a solution that would ensure high reliability, high scalability, and a stellar developer experience. Cash App is the financial hub for millions of people and often the first place an individual acquires bitcoin. It’s important to have a slick user experience and robust infrastructure that can onboard many new users. As a publicly traded company we take security seriously and need the ability to customize our wallet implementation in order to adhere to strict standards.")]),e._v(" "),t("p",[e._v("We chose LDK for various reasons over other implementations. It provided us with a lot of customizability and flexibility. The "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected",target:"_blank",rel:"noopener noreferrer"}},[e._v("Java bindings"),t("OutboundLink")],1),e._v(" let us develop in Kotlin, which is the preferred language for backend services. We also have a great working relationship with the "),t("a",{attrs:{href:"https://spiral.xyz/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spiral"),t("OutboundLink")],1),e._v(" folks, making it easy to collaborate on more advanced feature requests such as phantom invoices.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did")]),e._v(" "),t("p",[e._v("LDK allowed us to develop a scalable lightning node infrastructure. Cash App runs multiple wallet nodes and has strict parameters around opening channels and connecting to peers. We have logic that does advanced probing in the background in order to ensure an up-to-date snapshot of liquidity on the lightning network.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(354),alt:"CashApp architecture"}})]),e._v(" "),t("p",[e._v("Probing is done before every send, allowing us to pre-fetch a route and execute the send once the customer confirms. LDK’s "),t("a",{attrs:{href:"https://lightningdevkit.org/blog/introducing-phantom-node-payments/",target:"_blank",rel:"noopener noreferrer"}},[e._v("phantom node"),t("OutboundLink")],1),e._v(" feature makes it possible to generate invoices that can be claimed by more than one node. We use MySQL to save our channel state data + node metadata in order to quickly shut down and start up nodes at will on different servers. Additionally, LDK lets us run AB tests on different pathfinding algorithms.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("LDK made it possible to relatively quickly build an easy-to-use lightning wallet while adhering to the complicated constraints Cash App faces as a publicly traded company with tens of millions of users. Users can now instantly deposit and withdraw bitcoin to Cash App over lightning.")]),e._v(" "),t("p",[e._v("To learn more check out this "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=kbhL5RqL8Aw",target:"_blank",rel:"noopener noreferrer"}},[e._v("presentation"),t("OutboundLink")],1),e._v(" at btc++ explaining some of the trade-offs the Cash App team had to think about when comparing LDK to other solutions.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/22.d401d323.js b/assets/js/22.a2e6a166.js similarity index 98% rename from assets/js/22.d401d323.js rename to assets/js/22.a2e6a166.js index 0fc09627e..94342b609 100644 --- a/assets/js/22.d401d323.js +++ b/assets/js/22.a2e6a166.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{357:function(e,t,a){e.exports=a.p+"assets/img/ldk-roadmap.08c2e5db.png"},396:function(e,t,a){"use strict";a.r(t);var r=a(7),o=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("LDK is going to have a big year. Several key features are actively being developed or expected to be developed in the next few quarters. There are also a few projects of interest that don’t yet have any committed developers. If you want to get involved, hop into the "),t("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discord Server"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://github.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("GitHub repo"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("As a reminder, the LDK project is community-driven with no centralized authority. Anyone is welcome to contribute and propose ideas at any point. Additionally, it’s extremely important to listen to LDK users. The timeline listed below is just an estimate that may shift if a user request needs to be prioritized over another project.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(357),alt:"OM"}})]),e._v(" "),t("h1",{attrs:{id:"activecommited-projects"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#activecommited-projects"}},[e._v("#")]),e._v(" Active/Commited Projects")]),e._v(" "),t("h2",{attrs:{id:"ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node"}},[e._v("#")]),e._v(" LDK Node")]),e._v(" "),t("p",[e._v("LDK Node is an implementation of an LDK-based LN wallet and node. The LDK API is a powerful, extensive API that gives developers significant control, which can be intimidating to the uninitiated user. The LDK Node project delivers a fully functional LN wallet/node. The mobile-optimized recipe includes a "),t("a",{attrs:{href:"https://bitcoindevkit.org",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v("-based on-chain wallet, integration with Esplora/Electrum for block data, "),t("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[e._v("RGS"),t("OutboundLink")],1),e._v(" for performant mobile pathfinding, use of SQLite for local data storage, and VSS (once it is ready) for cloud backup of LN and other wallet state. The end result is a very small API surface (~15 methods vs. the >900 methods in LDK API), making it extremely easy to build a functioning mobile wallet in less than a day.")]),e._v(" "),t("p",[e._v("LDK Node can serve a variety of purposes for developers. For starters, it provides a simple way to get a mobile LN node/wallet up and running. Developers are then able to prototype the experience they’re imagining, and in some cases this will be sufficient for them to build and launch their product in production.")]),e._v(" "),t("p",[e._v("In other cases, developers will come to realize more customization is necessary, and they’ll have a couple of options at their disposal:")]),e._v(" "),t("ol",[t("li",[e._v("Build using the lower-level, more powerful LDK API and reference the LDK Node as an example.")]),e._v(" "),t("li",[e._v("Fork the LDK Node code and make custom modifications themselves. This has the benefit of reusing most of the LDK Node code. However, this requires knowledge of Rust and exposing more of the LDK API in LDK Node.")])]),e._v(" "),t("p",[e._v("While LDK Node is written in Rust, it is anticipated many languages will be supported through "),t("a",{attrs:{href:"https://github.com/mozilla/uniffi-rs",target:"_blank",rel:"noopener noreferrer"}},[e._v("UniFFI"),t("OutboundLink")],1),e._v(" or other mechanisms, including:")]),e._v(" "),t("ul",[t("li",[e._v("Java/Kotlin (near term)")]),e._v(" "),t("li",[e._v("Swift (near term)")]),e._v(" "),t("li",[e._v("Python (near term)")]),e._v(" "),t("li",[e._v("Flutter (near term)")]),e._v(" "),t("li",[e._v("React Native (near term)")]),e._v(" "),t("li",[e._v("Web (medium term)")])]),e._v(" "),t("p",[e._v("Through the development of LDK Node, it has been observed that most of the code can also be leveraged for a server configuration. The LDK project is conducting ongoing customer research to identify the needs and requirements for this configuration. The end result might be an LDK Node server daemon with a small RPC API.")]),e._v(" "),t("p",[e._v("The plan is to launch an initial version of LDK Node for mobile in Q2 2023 with continued improvements over time.")]),e._v(" "),t("h2",{attrs:{id:"bolt-12"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#bolt-12"}},[e._v("#")]),e._v(" BOLT 12")]),e._v(" "),t("p",[e._v("As of the 114 release, LDK supports onion messages and parsing BOLT 12 messages. It is expected to have full BOLT 12 send/receive support including blinded paths and compatibility with other BOLT 12 implementations in Q2 of 2023.")]),e._v(" "),t("h2",{attrs:{id:"anchor-outputs"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#anchor-outputs"}},[e._v("#")]),e._v(" Anchor Outputs")]),e._v(" "),t("p",[e._v("LDK should fully support anchor outputs by Q2 2023.")]),e._v(" "),t("h2",{attrs:{id:"vss"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#vss"}},[e._v("#")]),e._v(" VSS")]),e._v(" "),t("p",[e._v("VSS (Versioned Storage Service) addresses two problems. First, it offers a cloud backup for (encrypted) LN state and other wallet data that is crucial for recovery if the phone is lost or otherwise unavailable. Second, VSS will enable support for multi-device access to the same wallet, handling the synchronization properly so the wallet doesn’t wind up in a confused state. The first phase is expected to be released in Q2 2023. The second phase will be subject to monitoring for demand from wallets and may slip to 2024.")]),e._v(" "),t("h2",{attrs:{id:"improved-async-ness-in-ldk-api"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#improved-async-ness-in-ldk-api"}},[e._v("#")]),e._v(" Improved Async-ness in LDK API")]),e._v(" "),t("p",[e._v("The Rust language originally did not support async but it was added after the rust-lightning project started. Thus, LDK itself initially only supported synchronous calls, but over time LDK is adding more async support throughout the API.")]),e._v(" "),t("h2",{attrs:{id:"simple-taproot-channels"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#simple-taproot-channels"}},[e._v("#")]),e._v(" Simple Taproot Channels")]),e._v(" "),t("p",[e._v("Work has been ongoing since last fall to add "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/995",target:"_blank",rel:"noopener noreferrer"}},[e._v("simple taproot channels"),t("OutboundLink")],1),e._v(". LDK developers have provided feedback to the Taproot protocol specification which has resulted in improvements, and it is now close to finalizing simple channels. While LDK has its own MuSig implementation for development purposes, the LDK project will wait for the "),t("a",{attrs:{href:"https://github.com/BlockstreamResearch/secp256k1-zkp/pull/211",target:"_blank",rel:"noopener noreferrer"}},[e._v("libsecp implementation"),t("OutboundLink")],1),e._v(" as well as "),t("a",{attrs:{href:"https://github.com/BlockstreamResearch/rust-secp256k1-zkp/pull/48",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust bindings"),t("OutboundLink")],1),e._v(" in order to have the highest security assurances. The hope is that the spec, libsecp, and the LDK implementation all come together for a Q2 2023 release.")]),e._v(" "),t("h2",{attrs:{id:"dual-funded-channels"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dual-funded-channels"}},[e._v("#")]),e._v(" Dual-Funded Channels")]),e._v(" "),t("p",[e._v("Some work "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/issues/1621",target:"_blank",rel:"noopener noreferrer"}},[e._v("has begun"),t("OutboundLink")],1),e._v(" such as refactoring and implementing the "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/851",target:"_blank",rel:"noopener noreferrer"}},[e._v("interactive tx protocol"),t("OutboundLink")],1),e._v(". Dual-funded channels might make a release in Q2 2023, but more likely Q3 2023.")]),e._v(" "),t("h2",{attrs:{id:"splicing"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#splicing"}},[e._v("#")]),e._v(" Splicing")]),e._v(" "),t("p",[e._v("Work has not yet begun on splicing due to other commitments, but several developers have committed to working on it as a next project. Work is expected to commence in Q2. Given work hasn’t started yet, it is hard to estimate completion, but an aim for Q3 2023 seems reasonable at this point.")]),e._v(" "),t("h2",{attrs:{id:"async-payments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#async-payments"}},[e._v("#")]),e._v(" Async Payments")]),e._v(" "),t("p",[e._v("The "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989#issuecomment-1325389542",target:"_blank",rel:"noopener noreferrer"}},[e._v("async payments proposal"),t("OutboundLink")],1),e._v(" will substantially improve the mobile wallet user experience by allowing people to receive payments under any conditions. The general design and workflow has been "),t("a",{attrs:{href:"https://gist.github.com/remyers/e0d2bedb7bc87371d1bdbbb6fff2edd1",target:"_blank",rel:"noopener noreferrer"}},[e._v("mostly fleshed out"),t("OutboundLink")],1),e._v(". The initial plan is to build a prototype and improve the specification along the way.")]),e._v(" "),t("p",[e._v("The work will be broken down into two phases. The first phase will support async receive and the second will support async send. The reasoning behind this two stage approach is that the first phase has value on its own. Any custodial service, which will naturally have persistent internet, would then be able to reliably send payments to recipients without a persistent internet connection (mobile phones, web browser wallets, etc.).")]),e._v(" "),t("p",[e._v("The second phase is of course necessary for wallets sending from a phone or web browser. This will require support of trampoline in order to retry payments in a trustless way from the sender’s peer (eg an LSP).")]),e._v(" "),t("p",[e._v("LDK is just starting this development, so timeframes have large error bars, but probably the best case scenario would be delivering a working demonstration of phase 1 in Q3 2023 and phase 2 in Q4 2023. In addition to a working demonstration, it is expected to publish a complete specification for each phase that will be available for feedback by the development community.")]),e._v(" "),t("h2",{attrs:{id:"ptlcs"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ptlcs"}},[e._v("#")]),e._v(" PTLCs")]),e._v(" "),t("p",[e._v("The LDK project intends to contribute to the specification and development of PTLCs in 2023. The plan is to build upon previous work ("),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003278.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-December/003377.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(") by building a prototype and improving the specification. The ideal outcome is a specification that comes out later this year which gains developer consensus and a complete implementation in LDK. By 2024, hopefully there are multiple implementations and initial deployment throughout the network.")]),e._v(" "),t("h1",{attrs:{id:"prospective-future-projects"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#prospective-future-projects"}},[e._v("#")]),e._v(" Prospective Future Projects")]),e._v(" "),t("h2",{attrs:{id:"additional-language-bindings"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#additional-language-bindings"}},[e._v("#")]),e._v(" Additional Language Bindings")]),e._v(" "),t("p",[e._v("LDK already supports many languages, but there are several unsupported languages/frameworks that are used by existing applications, including:")]),e._v(" "),t("ul",[t("li",[e._v("C#")]),e._v(" "),t("li",[e._v("Python")]),e._v(" "),t("li",[e._v("Go")]),e._v(" "),t("li",[e._v("Flutter")])]),e._v(" "),t("h2",{attrs:{id:"custom-scripts"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#custom-scripts"}},[e._v("#")]),e._v(" Custom Scripts")]),e._v(" "),t("p",[e._v("LDK currently only supports the standard LN protocol spec script, however, it is possible to make LDK more flexible and allow 3rd parties to create custom scripts for applications such as taproot, DLCs, or Taro.")]),e._v(" "),t("h2",{attrs:{id:"dynamic-commitments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dynamic-commitments"}},[e._v("#")]),e._v(" Dynamic Commitments")]),e._v(" "),t("p",[e._v("See "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2022-March/003531.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("this mailing list post"),t("OutboundLink")],1),e._v(" for reference.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{356:function(e,t,a){e.exports=a.p+"assets/img/ldk-roadmap.08c2e5db.png"},394:function(e,t,a){"use strict";a.r(t);var r=a(7),o=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("LDK is going to have a big year. Several key features are actively being developed or expected to be developed in the next few quarters. There are also a few projects of interest that don’t yet have any committed developers. If you want to get involved, hop into the "),t("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discord Server"),t("OutboundLink")],1),e._v(" or "),t("a",{attrs:{href:"https://github.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("GitHub repo"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("As a reminder, the LDK project is community-driven with no centralized authority. Anyone is welcome to contribute and propose ideas at any point. Additionally, it’s extremely important to listen to LDK users. The timeline listed below is just an estimate that may shift if a user request needs to be prioritized over another project.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(356),alt:"OM"}})]),e._v(" "),t("h1",{attrs:{id:"activecommited-projects"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#activecommited-projects"}},[e._v("#")]),e._v(" Active/Commited Projects")]),e._v(" "),t("h2",{attrs:{id:"ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node"}},[e._v("#")]),e._v(" LDK Node")]),e._v(" "),t("p",[e._v("LDK Node is an implementation of an LDK-based LN wallet and node. The LDK API is a powerful, extensive API that gives developers significant control, which can be intimidating to the uninitiated user. The LDK Node project delivers a fully functional LN wallet/node. The mobile-optimized recipe includes a "),t("a",{attrs:{href:"https://bitcoindevkit.org",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v("-based on-chain wallet, integration with Esplora/Electrum for block data, "),t("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[e._v("RGS"),t("OutboundLink")],1),e._v(" for performant mobile pathfinding, use of SQLite for local data storage, and VSS (once it is ready) for cloud backup of LN and other wallet state. The end result is a very small API surface (~15 methods vs. the >900 methods in LDK API), making it extremely easy to build a functioning mobile wallet in less than a day.")]),e._v(" "),t("p",[e._v("LDK Node can serve a variety of purposes for developers. For starters, it provides a simple way to get a mobile LN node/wallet up and running. Developers are then able to prototype the experience they’re imagining, and in some cases this will be sufficient for them to build and launch their product in production.")]),e._v(" "),t("p",[e._v("In other cases, developers will come to realize more customization is necessary, and they’ll have a couple of options at their disposal:")]),e._v(" "),t("ol",[t("li",[e._v("Build using the lower-level, more powerful LDK API and reference the LDK Node as an example.")]),e._v(" "),t("li",[e._v("Fork the LDK Node code and make custom modifications themselves. This has the benefit of reusing most of the LDK Node code. However, this requires knowledge of Rust and exposing more of the LDK API in LDK Node.")])]),e._v(" "),t("p",[e._v("While LDK Node is written in Rust, it is anticipated many languages will be supported through "),t("a",{attrs:{href:"https://github.com/mozilla/uniffi-rs",target:"_blank",rel:"noopener noreferrer"}},[e._v("UniFFI"),t("OutboundLink")],1),e._v(" or other mechanisms, including:")]),e._v(" "),t("ul",[t("li",[e._v("Java/Kotlin (near term)")]),e._v(" "),t("li",[e._v("Swift (near term)")]),e._v(" "),t("li",[e._v("Python (near term)")]),e._v(" "),t("li",[e._v("Flutter (near term)")]),e._v(" "),t("li",[e._v("React Native (near term)")]),e._v(" "),t("li",[e._v("Web (medium term)")])]),e._v(" "),t("p",[e._v("Through the development of LDK Node, it has been observed that most of the code can also be leveraged for a server configuration. The LDK project is conducting ongoing customer research to identify the needs and requirements for this configuration. The end result might be an LDK Node server daemon with a small RPC API.")]),e._v(" "),t("p",[e._v("The plan is to launch an initial version of LDK Node for mobile in Q2 2023 with continued improvements over time.")]),e._v(" "),t("h2",{attrs:{id:"bolt-12"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#bolt-12"}},[e._v("#")]),e._v(" BOLT 12")]),e._v(" "),t("p",[e._v("As of the 114 release, LDK supports onion messages and parsing BOLT 12 messages. It is expected to have full BOLT 12 send/receive support including blinded paths and compatibility with other BOLT 12 implementations in Q2 of 2023.")]),e._v(" "),t("h2",{attrs:{id:"anchor-outputs"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#anchor-outputs"}},[e._v("#")]),e._v(" Anchor Outputs")]),e._v(" "),t("p",[e._v("LDK should fully support anchor outputs by Q2 2023.")]),e._v(" "),t("h2",{attrs:{id:"vss"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#vss"}},[e._v("#")]),e._v(" VSS")]),e._v(" "),t("p",[e._v("VSS (Versioned Storage Service) addresses two problems. First, it offers a cloud backup for (encrypted) LN state and other wallet data that is crucial for recovery if the phone is lost or otherwise unavailable. Second, VSS will enable support for multi-device access to the same wallet, handling the synchronization properly so the wallet doesn’t wind up in a confused state. The first phase is expected to be released in Q2 2023. The second phase will be subject to monitoring for demand from wallets and may slip to 2024.")]),e._v(" "),t("h2",{attrs:{id:"improved-async-ness-in-ldk-api"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#improved-async-ness-in-ldk-api"}},[e._v("#")]),e._v(" Improved Async-ness in LDK API")]),e._v(" "),t("p",[e._v("The Rust language originally did not support async but it was added after the rust-lightning project started. Thus, LDK itself initially only supported synchronous calls, but over time LDK is adding more async support throughout the API.")]),e._v(" "),t("h2",{attrs:{id:"simple-taproot-channels"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#simple-taproot-channels"}},[e._v("#")]),e._v(" Simple Taproot Channels")]),e._v(" "),t("p",[e._v("Work has been ongoing since last fall to add "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/995",target:"_blank",rel:"noopener noreferrer"}},[e._v("simple taproot channels"),t("OutboundLink")],1),e._v(". LDK developers have provided feedback to the Taproot protocol specification which has resulted in improvements, and it is now close to finalizing simple channels. While LDK has its own MuSig implementation for development purposes, the LDK project will wait for the "),t("a",{attrs:{href:"https://github.com/BlockstreamResearch/secp256k1-zkp/pull/211",target:"_blank",rel:"noopener noreferrer"}},[e._v("libsecp implementation"),t("OutboundLink")],1),e._v(" as well as "),t("a",{attrs:{href:"https://github.com/BlockstreamResearch/rust-secp256k1-zkp/pull/48",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust bindings"),t("OutboundLink")],1),e._v(" in order to have the highest security assurances. The hope is that the spec, libsecp, and the LDK implementation all come together for a Q2 2023 release.")]),e._v(" "),t("h2",{attrs:{id:"dual-funded-channels"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dual-funded-channels"}},[e._v("#")]),e._v(" Dual-Funded Channels")]),e._v(" "),t("p",[e._v("Some work "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/issues/1621",target:"_blank",rel:"noopener noreferrer"}},[e._v("has begun"),t("OutboundLink")],1),e._v(" such as refactoring and implementing the "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/851",target:"_blank",rel:"noopener noreferrer"}},[e._v("interactive tx protocol"),t("OutboundLink")],1),e._v(". Dual-funded channels might make a release in Q2 2023, but more likely Q3 2023.")]),e._v(" "),t("h2",{attrs:{id:"splicing"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#splicing"}},[e._v("#")]),e._v(" Splicing")]),e._v(" "),t("p",[e._v("Work has not yet begun on splicing due to other commitments, but several developers have committed to working on it as a next project. Work is expected to commence in Q2. Given work hasn’t started yet, it is hard to estimate completion, but an aim for Q3 2023 seems reasonable at this point.")]),e._v(" "),t("h2",{attrs:{id:"async-payments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#async-payments"}},[e._v("#")]),e._v(" Async Payments")]),e._v(" "),t("p",[e._v("The "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989#issuecomment-1325389542",target:"_blank",rel:"noopener noreferrer"}},[e._v("async payments proposal"),t("OutboundLink")],1),e._v(" will substantially improve the mobile wallet user experience by allowing people to receive payments under any conditions. The general design and workflow has been "),t("a",{attrs:{href:"https://gist.github.com/remyers/e0d2bedb7bc87371d1bdbbb6fff2edd1",target:"_blank",rel:"noopener noreferrer"}},[e._v("mostly fleshed out"),t("OutboundLink")],1),e._v(". The initial plan is to build a prototype and improve the specification along the way.")]),e._v(" "),t("p",[e._v("The work will be broken down into two phases. The first phase will support async receive and the second will support async send. The reasoning behind this two stage approach is that the first phase has value on its own. Any custodial service, which will naturally have persistent internet, would then be able to reliably send payments to recipients without a persistent internet connection (mobile phones, web browser wallets, etc.).")]),e._v(" "),t("p",[e._v("The second phase is of course necessary for wallets sending from a phone or web browser. This will require support of trampoline in order to retry payments in a trustless way from the sender’s peer (eg an LSP).")]),e._v(" "),t("p",[e._v("LDK is just starting this development, so timeframes have large error bars, but probably the best case scenario would be delivering a working demonstration of phase 1 in Q3 2023 and phase 2 in Q4 2023. In addition to a working demonstration, it is expected to publish a complete specification for each phase that will be available for feedback by the development community.")]),e._v(" "),t("h2",{attrs:{id:"ptlcs"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ptlcs"}},[e._v("#")]),e._v(" PTLCs")]),e._v(" "),t("p",[e._v("The LDK project intends to contribute to the specification and development of PTLCs in 2023. The plan is to build upon previous work ("),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003278.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-December/003377.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(") by building a prototype and improving the specification. The ideal outcome is a specification that comes out later this year which gains developer consensus and a complete implementation in LDK. By 2024, hopefully there are multiple implementations and initial deployment throughout the network.")]),e._v(" "),t("h1",{attrs:{id:"prospective-future-projects"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#prospective-future-projects"}},[e._v("#")]),e._v(" Prospective Future Projects")]),e._v(" "),t("h2",{attrs:{id:"additional-language-bindings"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#additional-language-bindings"}},[e._v("#")]),e._v(" Additional Language Bindings")]),e._v(" "),t("p",[e._v("LDK already supports many languages, but there are several unsupported languages/frameworks that are used by existing applications, including:")]),e._v(" "),t("ul",[t("li",[e._v("C#")]),e._v(" "),t("li",[e._v("Python")]),e._v(" "),t("li",[e._v("Go")]),e._v(" "),t("li",[e._v("Flutter")])]),e._v(" "),t("h2",{attrs:{id:"custom-scripts"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#custom-scripts"}},[e._v("#")]),e._v(" Custom Scripts")]),e._v(" "),t("p",[e._v("LDK currently only supports the standard LN protocol spec script, however, it is possible to make LDK more flexible and allow 3rd parties to create custom scripts for applications such as taproot, DLCs, or Taro.")]),e._v(" "),t("h2",{attrs:{id:"dynamic-commitments"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dynamic-commitments"}},[e._v("#")]),e._v(" Dynamic Commitments")]),e._v(" "),t("p",[e._v("See "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2022-March/003531.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("this mailing list post"),t("OutboundLink")],1),e._v(" for reference.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/23.89da4ce5.js b/assets/js/23.4993abf7.js similarity index 93% rename from assets/js/23.89da4ce5.js rename to assets/js/23.4993abf7.js index c258771d9..821c1022d 100644 --- a/assets/js/23.89da4ce5.js +++ b/assets/js/23.4993abf7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{362:function(e,n,t){e.exports=t.p+"assets/img/sensei-architecture.0959f7aa.svg"},399:function(e,n,t){"use strict";t.r(n);var a=t(7),i=Object(a.a)({},(function(){var e=this,n=e._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://l2.technology/sensei",target:"_blank",rel:"noopener noreferrer"}},[e._v("Sensei"),n("OutboundLink")],1),e._v(" is a lightning node application optimized to serve many nodes within a single instance. It offers a beautiful web interface for admins to manage nodes as well as an interface for individual nodes to perform all of the common lightning network tasks such as connecting to peers, opening and closing channels, and creating and paying invoices. Sensei exposes http and grpc interfaces, allowing automation and programmatic control of the nodes.")]),e._v(" "),n("p",[e._v("One goal of the project was to design an application that could make running multiple lightning nodes as lightweight as possible in terms of resource utilization. Sensei needed a lightning implementation that was designed for low-resource environments and could enable sharing of specific components across a set of nodes.")]),e._v(" "),n("h1",{attrs:{id:"what-we-did"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),n("p",[e._v("LDK’s flexibility was the main reason I chose LDK as Sensei’s lightning implementation over other options. I really needed a way for all of the nodes to share certain components (block data, network graph message handling, pathfinding, etc) and LDK allowed this functionality out of the box.")]),e._v(" "),n("figure",[n("img",{attrs:{src:t(362),alt:"Sensei architecture"}})]),e._v(" "),n("p",[e._v("To do something similar with the other implementations would have required maintaining project forks or running multiple instances of the full daemons. The former creates never-ending maintenance work and the latter could never achieve the desired performance characteristics.")]),e._v(" "),n("h1",{attrs:{id:"results"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),n("p",[e._v("LDK allowed a one-person development team to produce a standalone lightning node server with unique functionality. I was able to piece together the underlying lightning components exactly how I needed without having to maintain forks containing ugly hacks or be limited by the resource utilization of an existing daemon. LDK handles all of the low-level lightning network protocol details, which frees up my time to focus on Sensei’s core features. It’s still early days for Sensei but I’m already able to use it to run hundreds of lightning nodes on my laptop!")])])}),[],!1,null,null,null);n.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{357:function(e,n,t){e.exports=t.p+"assets/img/sensei-architecture.0959f7aa.svg"},396:function(e,n,t){"use strict";t.r(n);var a=t(7),i=Object(a.a)({},(function(){var e=this,n=e._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://l2.technology/sensei",target:"_blank",rel:"noopener noreferrer"}},[e._v("Sensei"),n("OutboundLink")],1),e._v(" is a lightning node application optimized to serve many nodes within a single instance. It offers a beautiful web interface for admins to manage nodes as well as an interface for individual nodes to perform all of the common lightning network tasks such as connecting to peers, opening and closing channels, and creating and paying invoices. Sensei exposes http and grpc interfaces, allowing automation and programmatic control of the nodes.")]),e._v(" "),n("p",[e._v("One goal of the project was to design an application that could make running multiple lightning nodes as lightweight as possible in terms of resource utilization. Sensei needed a lightning implementation that was designed for low-resource environments and could enable sharing of specific components across a set of nodes.")]),e._v(" "),n("h1",{attrs:{id:"what-we-did"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),n("p",[e._v("LDK’s flexibility was the main reason I chose LDK as Sensei’s lightning implementation over other options. I really needed a way for all of the nodes to share certain components (block data, network graph message handling, pathfinding, etc) and LDK allowed this functionality out of the box.")]),e._v(" "),n("figure",[n("img",{attrs:{src:t(357),alt:"Sensei architecture"}})]),e._v(" "),n("p",[e._v("To do something similar with the other implementations would have required maintaining project forks or running multiple instances of the full daemons. The former creates never-ending maintenance work and the latter could never achieve the desired performance characteristics.")]),e._v(" "),n("h1",{attrs:{id:"results"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),n("p",[e._v("LDK allowed a one-person development team to produce a standalone lightning node server with unique functionality. I was able to piece together the underlying lightning components exactly how I needed without having to maintain forks containing ugly hacks or be limited by the resource utilization of an existing daemon. LDK handles all of the low-level lightning network protocol details, which frees up my time to focus on Sensei’s core features. It’s still early days for Sensei but I’m already able to use it to run hundreds of lightning nodes on my laptop!")])])}),[],!1,null,null,null);n.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/24.1d23616c.js b/assets/js/24.c69b5bc3.js similarity index 95% rename from assets/js/24.1d23616c.js rename to assets/js/24.c69b5bc3.js index 25602692f..21ce48767 100644 --- a/assets/js/24.1d23616c.js +++ b/assets/js/24.c69b5bc3.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{363:function(e,t,a){e.exports=a.p+"assets/img/teos-architecture-diagram.3ab57d46.png"},401:function(e,t,a){"use strict";a.r(t);var n=a(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Eye of Satoshi (TEOS)"),t("OutboundLink")],1),e._v(" is a bitcoin watchtower with a specific focus on lightning. Watchtowers are third-party viewing services that help prevent people from cheating on the lightning network by constantly monitoring the bitcoin blockchain for channel breaches. If found, a watchtower will react by penalizing the misbehaving party and sending all funds to its counterpart.")]),e._v(" "),t("p",[e._v("In order for TEOS to work, information is needed from several different building blocks. This includes block data processing (such as reacting to forks/chain splits), interaction with a bitcoin node (for transaction broadcasting), and general tooling around bitcoin/lightning (transaction parsing, data encoding/decoding, lightning P2P messaging, etc).")]),e._v(" "),t("p",[e._v("TEOS does not have strong performance requirements, as data is checked in newly processed blocks approximately every 10 mins. However, if it services a substantial amount of nodes at once or channels with high traffic, it may need to compare processed info against huge amounts of data.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),t("p",[e._v("We initially had a Python implementation, but as the project evolved we realized it could be beneficial to switch to a language that was more robust and had better tooling. Rust was an obvious choice given how well it works for other bitcoin-related projects. Moving away from Python allowed us to drop a substantial amount of dependencies that were unmaintained or maintained by us, and instead use properly maintained counterparts.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(363),alt:"TEOS architecture"}})]),e._v(" "),t("p",[e._v("While it did take time to perform the Rust re-implementation, it was worth it for several reasons. LDK does a substantial amount of the low-level heavy lifting (e.g. reorg management), allowing us to remove several components of the original design and abstract interaction with bitcoind. Additionally, Python lacks proper support for most of lightning’s functionality, so we would have had to implement and maintain all of the related toolings to support lightning P2P communication features.")]),e._v(" "),t("p",[e._v("Furthermore, LDK supports various lightning features that we may need in the future, such as anchors. At the end of the day, LDK makes it possible to focus on the product/protocol you are building and care less about the low-level lightning/bitcoin parts that are needed.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("The TEOS codebase is now more robust and stable, making it easier to contribute to and integrate with other projects.")]),e._v(" "),t("p",[e._v("In terms of functionality, we recently reached the same state as the old Python codebase. We are currently focusing on new features and integrations. Additionally, using Rust and LDK has allowed us to build a healthier community. It’s easier to make improvements to a project when you use the same tools and literally speak the same language.")]),e._v(" "),t("p",[e._v("It's been a pleasure working with the LDK team. They’ve helped us solve several Rust and LDK issues, and have been open to accepting PRs and implementing new functionality that we require.")]),e._v(" "),t("p",[e._v("Learn how you can deploy your own TEOS watchtower on the Bitcoin Developers Youtube "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=8vzNB_NZt2A",target:"_blank",rel:"noopener noreferrer"}},[e._v("channel"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{362:function(e,t,a){e.exports=a.p+"assets/img/teos-architecture-diagram.3ab57d46.png"},402:function(e,t,a){"use strict";a.r(t);var n=a(7),o=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Eye of Satoshi (TEOS)"),t("OutboundLink")],1),e._v(" is a bitcoin watchtower with a specific focus on lightning. Watchtowers are third-party viewing services that help prevent people from cheating on the lightning network by constantly monitoring the bitcoin blockchain for channel breaches. If found, a watchtower will react by penalizing the misbehaving party and sending all funds to its counterpart.")]),e._v(" "),t("p",[e._v("In order for TEOS to work, information is needed from several different building blocks. This includes block data processing (such as reacting to forks/chain splits), interaction with a bitcoin node (for transaction broadcasting), and general tooling around bitcoin/lightning (transaction parsing, data encoding/decoding, lightning P2P messaging, etc).")]),e._v(" "),t("p",[e._v("TEOS does not have strong performance requirements, as data is checked in newly processed blocks approximately every 10 mins. However, if it services a substantial amount of nodes at once or channels with high traffic, it may need to compare processed info against huge amounts of data.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),t("p",[e._v("We initially had a Python implementation, but as the project evolved we realized it could be beneficial to switch to a language that was more robust and had better tooling. Rust was an obvious choice given how well it works for other bitcoin-related projects. Moving away from Python allowed us to drop a substantial amount of dependencies that were unmaintained or maintained by us, and instead use properly maintained counterparts.")]),e._v(" "),t("figure",[t("img",{attrs:{src:a(362),alt:"TEOS architecture"}})]),e._v(" "),t("p",[e._v("While it did take time to perform the Rust re-implementation, it was worth it for several reasons. LDK does a substantial amount of the low-level heavy lifting (e.g. reorg management), allowing us to remove several components of the original design and abstract interaction with bitcoind. Additionally, Python lacks proper support for most of lightning’s functionality, so we would have had to implement and maintain all of the related toolings to support lightning P2P communication features.")]),e._v(" "),t("p",[e._v("Furthermore, LDK supports various lightning features that we may need in the future, such as anchors. At the end of the day, LDK makes it possible to focus on the product/protocol you are building and care less about the low-level lightning/bitcoin parts that are needed.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("The TEOS codebase is now more robust and stable, making it easier to contribute to and integrate with other projects.")]),e._v(" "),t("p",[e._v("In terms of functionality, we recently reached the same state as the old Python codebase. We are currently focusing on new features and integrations. Additionally, using Rust and LDK has allowed us to build a healthier community. It’s easier to make improvements to a project when you use the same tools and literally speak the same language.")]),e._v(" "),t("p",[e._v("It's been a pleasure working with the LDK team. They’ve helped us solve several Rust and LDK issues, and have been open to accepting PRs and implementing new functionality that we require.")]),e._v(" "),t("p",[e._v("Learn how you can deploy your own TEOS watchtower on the Bitcoin Developers Youtube "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=8vzNB_NZt2A",target:"_blank",rel:"noopener noreferrer"}},[e._v("channel"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/25.170156ec.js b/assets/js/25.4ae746df.js similarity index 89% rename from assets/js/25.170156ec.js rename to assets/js/25.4ae746df.js index 17deb7af9..640533c6a 100644 --- a/assets/js/25.170156ec.js +++ b/assets/js/25.4ae746df.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{364:function(n,e,t){n.exports=t.p+"assets/img/ldk-block-processing.da054b79.svg"},408:function(n,e,t){"use strict";t.r(e);var o=t(7),a=Object(o.a)({},(function(){var n=this,e=n._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":n.$parent.slotKey}},[e("h2",{attrs:{id:"introduction"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[n._v("#")]),n._v(" Introduction")]),n._v(" "),e("p",[n._v("In this guide, we'll explore how to provide chain data to LDK upon startup and\nas new blocks are mined. This allows LDK to maintain channel state and monitor\nfor on-chain channel activity.")]),n._v(" "),e("p",[n._v("LDK maintains channels with your node's peers during the course of node\noperation. When a new channel is opened, the "),e("code",[n._v("ChannelManager")]),n._v(" will keep track of\nthe channel's state and tell the "),e("code",[n._v("ChainMonitor")]),n._v(" that a new channel should be\nwatched. The "),e("code",[n._v("ChainMonitor")]),n._v(" does so by maintaining a "),e("code",[n._v("ChannelMonitor")]),n._v(" for each\nchannel.")]),n._v(" "),e("p",[n._v("When a new block is mined, it is connected to the chain while other blocks may\nbe disconnected if reorganized out. Transactions are confirmed or unconfirmed\nduring this process. You are required to feed this activity to LDK which will\nprocess it by:")]),n._v(" "),e("ul",[e("li",[n._v("Updating channel state")]),n._v(" "),e("li",[n._v("Signaling back transactions to filter")]),n._v(" "),e("li",[n._v("Broadcasting transactions if necessary")])]),n._v(" "),e("p",[n._v("We will walk through this process as depicted here:")]),n._v(" "),e("figure",[e("img",{attrs:{src:t(364),alt:"LDK block processing"}})])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{363:function(n,e,t){n.exports=t.p+"assets/img/ldk-block-processing.da054b79.svg"},406:function(n,e,t){"use strict";t.r(e);var o=t(7),a=Object(o.a)({},(function(){var n=this,e=n._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":n.$parent.slotKey}},[e("h2",{attrs:{id:"introduction"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[n._v("#")]),n._v(" Introduction")]),n._v(" "),e("p",[n._v("In this guide, we'll explore how to provide chain data to LDK upon startup and\nas new blocks are mined. This allows LDK to maintain channel state and monitor\nfor on-chain channel activity.")]),n._v(" "),e("p",[n._v("LDK maintains channels with your node's peers during the course of node\noperation. When a new channel is opened, the "),e("code",[n._v("ChannelManager")]),n._v(" will keep track of\nthe channel's state and tell the "),e("code",[n._v("ChainMonitor")]),n._v(" that a new channel should be\nwatched. The "),e("code",[n._v("ChainMonitor")]),n._v(" does so by maintaining a "),e("code",[n._v("ChannelMonitor")]),n._v(" for each\nchannel.")]),n._v(" "),e("p",[n._v("When a new block is mined, it is connected to the chain while other blocks may\nbe disconnected if reorganized out. Transactions are confirmed or unconfirmed\nduring this process. You are required to feed this activity to LDK which will\nprocess it by:")]),n._v(" "),e("ul",[e("li",[n._v("Updating channel state")]),n._v(" "),e("li",[n._v("Signaling back transactions to filter")]),n._v(" "),e("li",[n._v("Broadcasting transactions if necessary")])]),n._v(" "),e("p",[n._v("We will walk through this process as depicted here:")]),n._v(" "),e("figure",[e("img",{attrs:{src:t(363),alt:"LDK block processing"}})])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/26.85cece84.js b/assets/js/26.f7f67ed2.js similarity index 89% rename from assets/js/26.85cece84.js rename to assets/js/26.f7f67ed2.js index e2c285b7a..6c3836491 100644 --- a/assets/js/26.85cece84.js +++ b/assets/js/26.f7f67ed2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{369:function(t,e,a){t.exports=a.p+"assets/img/ldk-architecture.c9d2bfc6.svg"},426:function(t,e,a){"use strict";a.r(e);var o=a(7),i=Object(o.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"architecture"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#architecture"}},[t._v("#")]),t._v(" Architecture")]),t._v(" "),e("figure",[e("img",{attrs:{src:a(369),alt:"Architecture"}})]),t._v(" "),e("p",[t._v("Firstly, LDK is not a daemon, but rather its own implementation of the Lightning protocol written as an SDK and designed to be compiled and executed in your application.")]),t._v(" "),e("p",[t._v("This makes it environment agnostic, allowing you to choose your own data storage, wallet, networking stack and blockchain monitoring. In the diagram above the boxes with dotted borders are LDK's modules — these must be configured with either default or custom implementations that you provide.")]),t._v(" "),e("p",[t._v("LDK also uses an event-driven architecture which allows for asynchronous result notification. For example you perform actions like making payments without waiting for the result and are later made aware via an event if the payment was successful or not.")]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Language Bindings")]),t._v(" "),e("p",[t._v("Although the core SDK is written in Rust, LDK supports many other programming languages. These include Java/Kotlin, Swift, JavaScript/TypeScript (Beta), C++ (Alpha). Check out "),e("RouterLink",{attrs:{to:"/examples/"}},[t._v("examples")]),t._v(" to see some of the implementations out in the wild!")],1)])])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{364:function(t,e,a){t.exports=a.p+"assets/img/ldk-architecture.c9d2bfc6.svg"},423:function(t,e,a){"use strict";a.r(e);var o=a(7),i=Object(o.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"architecture"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#architecture"}},[t._v("#")]),t._v(" Architecture")]),t._v(" "),e("figure",[e("img",{attrs:{src:a(364),alt:"Architecture"}})]),t._v(" "),e("p",[t._v("Firstly, LDK is not a daemon, but rather its own implementation of the Lightning protocol written as an SDK and designed to be compiled and executed in your application.")]),t._v(" "),e("p",[t._v("This makes it environment agnostic, allowing you to choose your own data storage, wallet, networking stack and blockchain monitoring. In the diagram above the boxes with dotted borders are LDK's modules — these must be configured with either default or custom implementations that you provide.")]),t._v(" "),e("p",[t._v("LDK also uses an event-driven architecture which allows for asynchronous result notification. For example you perform actions like making payments without waiting for the result and are later made aware via an event if the payment was successful or not.")]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Language Bindings")]),t._v(" "),e("p",[t._v("Although the core SDK is written in Rust, LDK supports many other programming languages. These include Java/Kotlin, Swift, JavaScript/TypeScript (Beta), C++ (Alpha). Check out "),e("RouterLink",{attrs:{to:"/examples/"}},[t._v("examples")]),t._v(" to see some of the implementations out in the wild!")],1)])])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/27.f0136cc0.js b/assets/js/27.9292eeb3.js similarity index 93% rename from assets/js/27.f0136cc0.js rename to assets/js/27.9292eeb3.js index c54663085..27e5050a6 100644 --- a/assets/js/27.f0136cc0.js +++ b/assets/js/27.9292eeb3.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{370:function(e,n,t){e.exports=t.p+"assets/img/ldk-peer-management.ac42ca47.svg"},430:function(e,n,t){"use strict";t.r(n);var r=t(7),o=Object(r.a)({},(function(){var e=this,n=e._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"peer-management"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#peer-management"}},[e._v("#")]),e._v(" Peer Management")]),e._v(" "),n("figure",[n("img",{attrs:{src:t(370),alt:"Peer Management"}})]),e._v(" "),n("p",[e._v("One of the first things you'll need to do when building your own Lightning node is connect to a peer. In LDK this is handled by the "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("PeerManager")]),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("p",[e._v("The "),n("code",[e._v("PeerManager")]),e._v(" has two dependencies:")]),e._v(" "),n("ul",[n("li",[e._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("ChannelManager")]),n("OutboundLink")],1),e._v(" that enables it to notify peers when it wants to do things such as open channels.")]),e._v(" "),n("li",[e._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.P2PGossipSync.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("P2PGossipSync")]),n("OutboundLink")],1),e._v(" that understands when peers you are connected to send you gossip messages, enables you to forward messages, announce channel opens and more.")])]),e._v(" "),n("p",[e._v("Since LDK knows nothing about your networking stack, you'll need to implement your own networking logic in order to connect to peers on the network. Provide LDK with raw TCP/IP socket data and the library will handle the rest for you.")]),e._v(" "),n("p",[e._v("LDK also handles a number of background tasks that need to happen periodically via "),n("a",{attrs:{href:"https://docs.rs/lightning-background-processor/*/lightning_background_processor/struct.BackgroundProcessor.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("BackgroundProcessor")]),n("OutboundLink")],1)]),e._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[e._v("Default Implementation")]),e._v(" "),n("p",[e._v("If you are developing in a Rust "),n("a",{attrs:{href:"https://tokio.rs/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Tokio"),n("OutboundLink")],1),e._v(" environment, LDK ships with a socket handling "),n("a",{attrs:{href:"https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/",target:"_blank",rel:"noopener noreferrer"}},[e._v("crate"),n("OutboundLink")],1),e._v(" that let's you easily create new connections with peers.")])])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{368:function(e,n,t){e.exports=t.p+"assets/img/ldk-peer-management.ac42ca47.svg"},428:function(e,n,t){"use strict";t.r(n);var r=t(7),o=Object(r.a)({},(function(){var e=this,n=e._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"peer-management"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#peer-management"}},[e._v("#")]),e._v(" Peer Management")]),e._v(" "),n("figure",[n("img",{attrs:{src:t(368),alt:"Peer Management"}})]),e._v(" "),n("p",[e._v("One of the first things you'll need to do when building your own Lightning node is connect to a peer. In LDK this is handled by the "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("PeerManager")]),n("OutboundLink")],1),e._v(".")]),e._v(" "),n("p",[e._v("The "),n("code",[e._v("PeerManager")]),e._v(" has two dependencies:")]),e._v(" "),n("ul",[n("li",[e._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("ChannelManager")]),n("OutboundLink")],1),e._v(" that enables it to notify peers when it wants to do things such as open channels.")]),e._v(" "),n("li",[e._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.P2PGossipSync.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("P2PGossipSync")]),n("OutboundLink")],1),e._v(" that understands when peers you are connected to send you gossip messages, enables you to forward messages, announce channel opens and more.")])]),e._v(" "),n("p",[e._v("Since LDK knows nothing about your networking stack, you'll need to implement your own networking logic in order to connect to peers on the network. Provide LDK with raw TCP/IP socket data and the library will handle the rest for you.")]),e._v(" "),n("p",[e._v("LDK also handles a number of background tasks that need to happen periodically via "),n("a",{attrs:{href:"https://docs.rs/lightning-background-processor/*/lightning_background_processor/struct.BackgroundProcessor.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[e._v("BackgroundProcessor")]),n("OutboundLink")],1)]),e._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[e._v("Default Implementation")]),e._v(" "),n("p",[e._v("If you are developing in a Rust "),n("a",{attrs:{href:"https://tokio.rs/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Tokio"),n("OutboundLink")],1),e._v(" environment, LDK ships with a socket handling "),n("a",{attrs:{href:"https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/",target:"_blank",rel:"noopener noreferrer"}},[e._v("crate"),n("OutboundLink")],1),e._v(" that let's you easily create new connections with peers.")])])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/28.f555e114.js b/assets/js/28.1cb32e6c.js similarity index 91% rename from assets/js/28.f555e114.js rename to assets/js/28.1cb32e6c.js index e70b41a2b..939c96ccf 100644 --- a/assets/js/28.f555e114.js +++ b/assets/js/28.1cb32e6c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{379:function(t,e,o){"use strict";o.r(e);var s=o(259);const n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."];var a={name:"NotFound",components:{LayoutWrap:s.a},methods:{getMsg:()=>n[Math.floor(Math.random()*n.length)]}},h=o(7),i=Object(h.a)(a,(function(){var t=this._self._c;return t("LayoutWrap",[t("main",{staticClass:"page"},[t("div",{staticClass:"theme-default-content"},[t("h1",[this._v("404 - Not Found")]),this._v(" "),t("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),t("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{377:function(t,e,o){"use strict";o.r(e);var s=o(259);const n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."];var a={name:"NotFound",components:{LayoutWrap:s.a},methods:{getMsg:()=>n[Math.floor(Math.random()*n.length)]}},h=o(7),i=Object(h.a)(a,(function(){var t=this._self._c;return t("LayoutWrap",[t("main",{staticClass:"page"},[t("div",{staticClass:"theme-default-content"},[t("h1",[this._v("404 - Not Found")]),this._v(" "),t("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),t("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/29.6d9673ce.js b/assets/js/29.31ad8e54.js similarity index 96% rename from assets/js/29.6d9673ce.js rename to assets/js/29.31ad8e54.js index cdc6b36a2..3d4da5d3b 100644 --- a/assets/js/29.6d9673ce.js +++ b/assets/js/29.31ad8e54.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{386:function(e,t,a){"use strict";a.r(t);a(109);var s={props:{name:{type:String,default:"default"},isolated:{type:Boolean,default:!1},languages:{type:Object,required:!1}},data(){return{selectedLanguage:this.languages?Object.keys(this.languages)[0]:null,actualLanguages:this.languages}},computed:{root(){let e,t=this;for(;e=t.$parent;)t=e;return t},localStorageKey(){return"vuepress-plugin-code-switcher@"+this.name}},methods:{switchLanguage(e){if(this.isolated)return this.selectedLanguage=e;"undefined"!=typeof localStorage&&localStorage.setItem(this.localStorageKey,e),this.root.$emit("change",{name:this.name,value:e})},setConfiguredDefaultLanguages(){if(this.languages)return;const e=this.$page.codeSwitcherOptions;e&&e.groups&&e.groups[this.name]&&(this.actualLanguages=e.groups[this.name],this.selectedLanguage=Object.keys(this.actualLanguages)[0])}},created(){if(!this.isolated){if(this.setConfiguredDefaultLanguages(),!this.actualLanguages)throw new Error('You must specify either the "languages" prop or use the "groups" option when configuring the plugin.');if("undefined"!=typeof localStorage){let e=localStorage.getItem(this.localStorageKey);e&&-1!==Object.keys(this.actualLanguages).indexOf(e)&&(this.selectedLanguage=e)}this.root.$on("change",({name:e,value:t})=>{e===this.name&&(this.selectedLanguage=t)})}}},n=a(7),u=Object(n.a)(s,(function(){var e=this,t=e._self._c;return t("div",{staticClass:"code-switcher"},[t("div",{staticClass:"tab-header"},[t("ul",e._l(e.actualLanguages,(function(a,s){return t("li",{key:s,class:{active:e.selectedLanguage===s},on:{click:function(t){return e.switchLanguage(s)}}},[e._v(" "+e._s(a)+"\n ")])})),0)]),e._v(" "),e._l(e.actualLanguages,(function(a,s){return t("div",{directives:[{name:"show",rawName:"v-show",value:s===e.selectedLanguage,expression:"shorthand === selectedLanguage"}],key:s,staticClass:"tab-content"},[e._t(s)],2)}))],2)}),[],!1,null,null,null);t.default=u.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{384:function(e,t,a){"use strict";a.r(t);a(109);var s={props:{name:{type:String,default:"default"},isolated:{type:Boolean,default:!1},languages:{type:Object,required:!1}},data(){return{selectedLanguage:this.languages?Object.keys(this.languages)[0]:null,actualLanguages:this.languages}},computed:{root(){let e,t=this;for(;e=t.$parent;)t=e;return t},localStorageKey(){return"vuepress-plugin-code-switcher@"+this.name}},methods:{switchLanguage(e){if(this.isolated)return this.selectedLanguage=e;"undefined"!=typeof localStorage&&localStorage.setItem(this.localStorageKey,e),this.root.$emit("change",{name:this.name,value:e})},setConfiguredDefaultLanguages(){if(this.languages)return;const e=this.$page.codeSwitcherOptions;e&&e.groups&&e.groups[this.name]&&(this.actualLanguages=e.groups[this.name],this.selectedLanguage=Object.keys(this.actualLanguages)[0])}},created(){if(!this.isolated){if(this.setConfiguredDefaultLanguages(),!this.actualLanguages)throw new Error('You must specify either the "languages" prop or use the "groups" option when configuring the plugin.');if("undefined"!=typeof localStorage){let e=localStorage.getItem(this.localStorageKey);e&&-1!==Object.keys(this.actualLanguages).indexOf(e)&&(this.selectedLanguage=e)}this.root.$on("change",({name:e,value:t})=>{e===this.name&&(this.selectedLanguage=t)})}}},n=a(7),u=Object(n.a)(s,(function(){var e=this,t=e._self._c;return t("div",{staticClass:"code-switcher"},[t("div",{staticClass:"tab-header"},[t("ul",e._l(e.actualLanguages,(function(a,s){return t("li",{key:s,class:{active:e.selectedLanguage===s},on:{click:function(t){return e.switchLanguage(s)}}},[e._v(" "+e._s(a)+"\n ")])})),0)]),e._v(" "),e._l(e.actualLanguages,(function(a,s){return t("div",{directives:[{name:"show",rawName:"v-show",value:s===e.selectedLanguage,expression:"shorthand === selectedLanguage"}],key:s,staticClass:"tab-content"},[e._t(s)],2)}))],2)}),[],!1,null,null,null);t.default=u.exports}}]); \ No newline at end of file diff --git a/assets/js/30.0f8b973a.js b/assets/js/30.c4cc7be4.js similarity index 98% rename from assets/js/30.0f8b973a.js rename to assets/js/30.c4cc7be4.js index 47af66efe..1413f41a7 100644 --- a/assets/js/30.0f8b973a.js +++ b/assets/js/30.c4cc7be4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{389:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("code",[e._v("v0.0.116")]),e._v(" of LDK with added support for opening channels with "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/anchor-outputs",target:"_blank",rel:"noopener noreferrer"}},[e._v("anchor\noutputs"),t("OutboundLink")],1),e._v(" is live. This much-requested feature\nbrings multiple security and usability improvements to Lightning channels.")]),e._v(" "),t("p",[e._v("Lightning channels rely on pre-signed transactions that participants broadcast to the network if\nthey wish to close a channel unilaterally, e.g., when their counterparty is offline. Before\nintroducing anchor outputs to the Lightning protocol, participants continually negotiated their\ncommitment transaction’s fees based on the current block-space demand. This fee negotiation\nunfortunately came with its own set of problems. If participants disagreed on the proposed fee\nrange, a unilateral close made the channel unusable. Underestimating the required fee could result\nin loss of funds if an HTLC needed to be resolved on-chain, and overestimating would misallocate the\nchannel balance towards fees, potentially rendering the channel useless.")]),e._v(" "),t("p",[e._v("With anchor outputs, participants can now contribute the majority of fees required at the time of\nbroadcast by bumping the commitment transaction's fee via a child transaction using the\n"),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/cpfp",target:"_blank",rel:"noopener noreferrer"}},[e._v("Child-Pays-For-Parent (CPFP)"),t("OutboundLink")],1),e._v(" fee-bumping mechanism. A small\nportion of fees must still be allocated to commitment transactions to ensure they can enter nodes'\nmempools independently. This will be required until "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/package-relay",target:"_blank",rel:"noopener noreferrer"}},[e._v("package\nrelay"),t("OutboundLink")],1),e._v(" is deployed network-wide. At that point, we\ncan have a fixed 1 sat/vB commitment transaction that is likely to do away with the fee negotiation\nonce and for all, eliminating the most common cause of unilateral closes that we see today.")]),e._v(" "),t("p",[e._v("Given LDK's modularized design, support for anchor outputs posed a few challenges. As a\nLightning-only library, we do not include an on-chain wallet as a traditional node implementation\nwould, requiring manual integration work by the application developer. However, we were able to\nleverage our existing "),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/events/index.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("event-based\nAPI"),t("OutboundLink")],1),e._v(" to communicate that a commitment\nor HTLC transaction's fee needs to be bumped. The handling of these events is often non-trivial, so\nwe added a utility\n("),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/events/bump_transaction/struct.BumpTransactionEventHandler.html",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("BumpTransactionEventHandler")]),t("OutboundLink")],1),e._v(")\nto simplify required integration work. With this utility, an application developer only needs to\nprovide a view into their on-chain wallet for LDK to access confirmed UTXOs and sign them.")]),e._v(" "),t("p",[e._v("Note that node operators need to maintain a reserve of confirmed funds if they wish to exit a\nchannel unilaterally. LDK will not ensure this reserve is enforced, but we’re exploring "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/issues/2320",target:"_blank",rel:"noopener noreferrer"}},[e._v("possible\nways to do so"),t("OutboundLink")],1),e._v(". Without such\nenforcement, a node may open or accept more channels than its provisioned reserve allows it to\nhandle, potentially resulting in a loss of funds if any HTLCs need to be resolved on-chain. In the\nmeantime, application developers must determine whether their use case warrants such enforcement,\nthen implement it themselves. For example, a mobile user connected to a LSP could always defer to\nthe LSP to broadcast the latest state so that the user wouldn’t need to maintain a reserve.")]),e._v(" "),t("p",[e._v("While the feature is now available, we still consider it experimental. We're always seeking feedback\non how to improve our API and provide a better developer experience.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{385:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[t("code",[e._v("v0.0.116")]),e._v(" of LDK with added support for opening channels with "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/anchor-outputs",target:"_blank",rel:"noopener noreferrer"}},[e._v("anchor\noutputs"),t("OutboundLink")],1),e._v(" is live. This much-requested feature\nbrings multiple security and usability improvements to Lightning channels.")]),e._v(" "),t("p",[e._v("Lightning channels rely on pre-signed transactions that participants broadcast to the network if\nthey wish to close a channel unilaterally, e.g., when their counterparty is offline. Before\nintroducing anchor outputs to the Lightning protocol, participants continually negotiated their\ncommitment transaction’s fees based on the current block-space demand. This fee negotiation\nunfortunately came with its own set of problems. If participants disagreed on the proposed fee\nrange, a unilateral close made the channel unusable. Underestimating the required fee could result\nin loss of funds if an HTLC needed to be resolved on-chain, and overestimating would misallocate the\nchannel balance towards fees, potentially rendering the channel useless.")]),e._v(" "),t("p",[e._v("With anchor outputs, participants can now contribute the majority of fees required at the time of\nbroadcast by bumping the commitment transaction's fee via a child transaction using the\n"),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/cpfp",target:"_blank",rel:"noopener noreferrer"}},[e._v("Child-Pays-For-Parent (CPFP)"),t("OutboundLink")],1),e._v(" fee-bumping mechanism. A small\nportion of fees must still be allocated to commitment transactions to ensure they can enter nodes'\nmempools independently. This will be required until "),t("a",{attrs:{href:"https://bitcoinops.org/en/topics/package-relay",target:"_blank",rel:"noopener noreferrer"}},[e._v("package\nrelay"),t("OutboundLink")],1),e._v(" is deployed network-wide. At that point, we\ncan have a fixed 1 sat/vB commitment transaction that is likely to do away with the fee negotiation\nonce and for all, eliminating the most common cause of unilateral closes that we see today.")]),e._v(" "),t("p",[e._v("Given LDK's modularized design, support for anchor outputs posed a few challenges. As a\nLightning-only library, we do not include an on-chain wallet as a traditional node implementation\nwould, requiring manual integration work by the application developer. However, we were able to\nleverage our existing "),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/events/index.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("event-based\nAPI"),t("OutboundLink")],1),e._v(" to communicate that a commitment\nor HTLC transaction's fee needs to be bumped. The handling of these events is often non-trivial, so\nwe added a utility\n("),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/events/bump_transaction/struct.BumpTransactionEventHandler.html",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("BumpTransactionEventHandler")]),t("OutboundLink")],1),e._v(")\nto simplify required integration work. With this utility, an application developer only needs to\nprovide a view into their on-chain wallet for LDK to access confirmed UTXOs and sign them.")]),e._v(" "),t("p",[e._v("Note that node operators need to maintain a reserve of confirmed funds if they wish to exit a\nchannel unilaterally. LDK will not ensure this reserve is enforced, but we’re exploring "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/issues/2320",target:"_blank",rel:"noopener noreferrer"}},[e._v("possible\nways to do so"),t("OutboundLink")],1),e._v(". Without such\nenforcement, a node may open or accept more channels than its provisioned reserve allows it to\nhandle, potentially resulting in a loss of funds if any HTLCs need to be resolved on-chain. In the\nmeantime, application developers must determine whether their use case warrants such enforcement,\nthen implement it themselves. For example, a mobile user connected to a LSP could always defer to\nthe LSP to broadcast the latest state so that the user wouldn’t need to maintain a reserve.")]),e._v(" "),t("p",[e._v("While the feature is now available, we still consider it experimental. We're always seeking feedback\non how to improve our API and provide a better developer experience.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/31.d6266bbc.js b/assets/js/31.dca02756.js similarity index 99% rename from assets/js/31.d6266bbc.js rename to assets/js/31.dca02756.js index 401a7a7c6..dc249a3b5 100644 --- a/assets/js/31.d6266bbc.js +++ b/assets/js/31.dca02756.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{390:function(t,n,e){"use strict";e.r(n);var s=e(7),a=Object(s.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK Node"),n("OutboundLink")],1),t._v(" is a ready-to-go Lightning node library built using "),n("a",{attrs:{href:"https://lightningdevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK"),n("OutboundLink")],1),t._v(" and "),n("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),n("OutboundLink")],1),t._v(". LDK Node provides a straightforward interface and an integrated on-chain wallet, enabling users to quickly and easily set up a self-custodial Lightning node. With LDK Node, developers can get a Lightning Node up and running within a day.")]),t._v(" "),n("h2",{attrs:{id:"a-lightweight-solution"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#a-lightweight-solution"}},[t._v("#")]),t._v(" A Lightweight Solution")]),t._v(" "),n("p",[t._v("LDK fully implements the Lightning protocol as a highly modular Rust library. LDK's flexibility allows developers to integrate Lightning functionality into "),n("a",{attrs:{href:"https://lightningdevkit.org/case-studies/",target:"_blank",rel:"noopener noreferrer"}},[t._v("many types of applications"),n("OutboundLink")],1),t._v(", including those with pre-existing infrastructure or complex architectures. The public API comprises more than 900 exposed methods, letting users adjust and interact with protocol layers in great detail. While this customization is great for builders, it often comes with the added cost of increased complexity.")]),t._v(" "),n("p",[t._v("LDK provides sane defaults where possible. However, correctly and effectively setting up all interconnected modules requires a deeper understanding of protocol fundamentals and some familiarity with the LDK API. Moreover, because LDK adheres to the separation-of-concerns principle, it is wallet-agnostic and deliberately doesn't come with an included on-chain wallet. Therefore, the integration with a suitable on-chain wallet is left to the user.")]),t._v(" "),n("p",[t._v("As a result, it can take a bit of effort to get started with LDK. That's why we created LDK Node, a more fully-baked solution.")]),t._v(" "),n("h2",{attrs:{id:"ldk-node-simplifying-self-custodial-lightning-integration"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-simplifying-self-custodial-lightning-integration"}},[t._v("#")]),t._v(" LDK Node: Simplifying Self-custodial Lightning Integration")]),t._v(" "),n("p",[t._v("LDK Node was designed to hide protocol complexities without infringing on usability. LDK Node's much smaller API surface makes its reduced complexity evident. Compared to LDK's above 900 exposed methods, LDK Node's API currently only encompasses around 30 API calls. While simplicity and minimalism are at its core, LDK Node remains configurable enough to operate a fully functional self-custodial Lightning node in various use cases.")]),t._v(" "),n("p",[t._v("There is a trade-off between simplicity and expressiveness when designing an API while handling protocol complexity. The API needs to become more complicated to increase configurability and the interconnectivity of components. As a result, the user must spend more time examining, learning, and scrutinizing the API before finally being able to use it. While the LDK API errs on the side of expressiveness, LDK Node leans towards simplicity.")]),t._v(" "),n("p",[t._v("This first release of LDK Node comes with an opinionated set of design choices and ready-to-go modules:")]),t._v(" "),n("ul",[n("li",[t._v("The integrated "),n("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),n("OutboundLink")],1),t._v(" wallet handles on-chain data.")]),t._v(" "),n("li",[t._v("Chain data is sourced from an "),n("a",{attrs:{href:"https://github.com/Blockstream/esplora",target:"_blank",rel:"noopener noreferrer"}},[t._v("Esplora"),n("OutboundLink")],1),t._v(" server, while support for Electrum and "),n("code",[t._v("bitcoind")]),t._v(" RPC will follow soon.")]),t._v(" "),n("li",[t._v("Wallet and channel state may be persisted to an "),n("a",{attrs:{href:"https://sqlite.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SQLite"),n("OutboundLink")],1),t._v(" database, to file system, or to a custom back-end to be implemented by the user. Support for "),n("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[t._v("Versioned Storage Service (VSS)"),n("OutboundLink")],1),t._v(" will follow soon.")]),t._v(" "),n("li",[t._v("Gossip data may be sourced via Lightning's peer-to-peer network or the "),n("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/0.0.115/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rapid Gossip Sync (RGS)"),n("OutboundLink")],1),t._v(" protocol.")]),t._v(" "),n("li",[t._v("Entropy for Lightning and on-chain wallets may be sourced from raw bytes or a "),n("a",{attrs:{href:"https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki",target:"_blank",rel:"noopener noreferrer"}},[t._v("BIP39"),n("OutboundLink")],1),t._v(" mnemonic. In addition, LDK Node offers the means to generate and persist the entropy bytes to disk.")])]),t._v(" "),n("h2",{attrs:{id:"mobile-first-self-custody"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#mobile-first-self-custody"}},[t._v("#")]),t._v(" Mobile-first Self-Custody")]),t._v(" "),n("p",[t._v("The main goal of the Lightning protocol is to enable fast, private, and secure Bitcoin transactions for the end-user. However, today most Lightning deployments are custodial services that may only be queried by the client device in the end-user's hands. This is understandable: deploying self-custodial Lightning nodes on end-user devices can take a lot of work to get right, as there are many pitfalls to avoid.")]),t._v(" "),n("p",[t._v("To this end, one of the primary goals of LDK Node is to simplify the integration of self-custodial Lightning nodes in mobile applications. The features of the initial release are centered around mobile deployments. The integration with an Esplora chain data source and a Rapid Gossip Sync server allows the node to operate in mobile environments that may be limited in terms of bandwidth and overall traffic quota.")]),t._v(" "),n("p",[t._v("LDK Node itself is written in "),n("a",{attrs:{href:"https://www.rust-lang.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust"),n("OutboundLink")],1),t._v(" and may therefore be natively added as a library dependency to any "),n("code",[t._v("std")]),t._v(" Rust program. However, beyond its Rust API, it offers "),n("a",{attrs:{href:"https://www.swift.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Swift"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://kotlinlang.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kotlin"),n("OutboundLink")],1),t._v(", and "),n("a",{attrs:{href:"https://www.python.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Python"),n("OutboundLink")],1),t._v(" language bindings based on "),n("a",{attrs:{href:"https://github.com/mozilla/uniffi-rs/",target:"_blank",rel:"noopener noreferrer"}},[t._v("UniFFI"),n("OutboundLink")],1),t._v(". Moreover, "),n("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-flutter",target:"_blank",rel:"noopener noreferrer"}},[t._v("Flutter"),n("OutboundLink")],1),t._v(" bindings are also available to allow usage of the LDK Node library in mobile environments.")]),t._v(" "),n("h2",{attrs:{id:"getting-started"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting Started")]),t._v(" "),n("p",[t._v("The primary abstraction of the library is the "),n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/struct.Node.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Node")]),n("OutboundLink")],1),t._v(", which can be retrieved by setting up and configuring a "),n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/struct.Builder.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Builder")]),n("OutboundLink")],1),t._v(" to your liking and calling one of the "),n("code",[t._v("build")]),t._v(" methods. "),n("code",[t._v("Node")]),t._v(" can then be controlled via commands such as "),n("code",[t._v("start")]),t._v(", "),n("code",[t._v("stop")]),t._v(", "),n("code",[t._v("connect_open_channel")]),t._v(", "),n("code",[t._v("send_payment")]),t._v(", etc.")]),t._v(" "),n("p",[n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Read Full API Documentation"),n("OutboundLink")],1)]),t._v(" "),n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetAddress")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning_invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("secp256k1"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FromStr")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_esplora_server")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://blockstream.info/testnet/api"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_gossip_source_rgs")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://rapidsync.lightningdevkit.org/testnet/snapshot"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" builder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" funding_address "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_onchain_address")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. fund address ..")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node_id "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"NODE_ID"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node_addr "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetAddress")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"IP_ADDR:PORT"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect_open_channel")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" node_addr"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("wait_next_event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EVENT: {:?}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("event_handled")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INVOICE_STR"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("stop")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"outlook"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#outlook"}},[t._v("#")]),t._v(" Outlook")]),t._v(" "),n("p",[t._v("The 0.1 release is only the beginning for LDK Node. Development for the next release has already started, and we'll be looking to add support for sourcing chain data from Electrum or "),n("code",[t._v("bitcoind")]),t._v(" RPC, and supporting persistence to a "),n("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[t._v("VSS"),n("OutboundLink")],1),t._v(" backend (see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/issues/107",target:"_blank",rel:"noopener noreferrer"}},[t._v("v0.2 tracking issue"),n("OutboundLink")],1),t._v("). Additionally, integration with the "),n("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSP specification"),n("OutboundLink")],1),t._v(" is actively being worked on (see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-lsp-client",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSP Client"),n("OutboundLink")],1),t._v(" repository) and will come to LDK Node as soon as it's ready. Beyond these planned feature updates to the LDK Node library, we're also considering further deployment targets, including adding server-grade modules in the future.")]),t._v(" "),n("h2",{attrs:{id:"further-resources"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#further-resources"}},[t._v("#")]),t._v(" Further Resources")]),t._v(" "),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github Repository"),n("OutboundLink")],1)]),t._v(" "),n("li",[n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Documentation"),n("OutboundLink")],1)]),t._v(" "),n("li",[n("a",{attrs:{href:"https://crates.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Crate"),n("OutboundLink")],1)])]),t._v(" "),n("h2",{attrs:{id:"showcases"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#showcases"}},[t._v("#")]),t._v(" Showcases")]),t._v(" "),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/reez/Monday",target:"_blank",rel:"noopener noreferrer"}},[t._v("Monday Wallet: Example wallet built with on LDK Node Swift bindings"),n("OutboundLink")],1)])])])}),[],!1,null,null,null);n.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{386:function(t,n,e){"use strict";e.r(n);var s=e(7),a=Object(s.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("p",[n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK Node"),n("OutboundLink")],1),t._v(" is a ready-to-go Lightning node library built using "),n("a",{attrs:{href:"https://lightningdevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK"),n("OutboundLink")],1),t._v(" and "),n("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),n("OutboundLink")],1),t._v(". LDK Node provides a straightforward interface and an integrated on-chain wallet, enabling users to quickly and easily set up a self-custodial Lightning node. With LDK Node, developers can get a Lightning Node up and running within a day.")]),t._v(" "),n("h2",{attrs:{id:"a-lightweight-solution"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#a-lightweight-solution"}},[t._v("#")]),t._v(" A Lightweight Solution")]),t._v(" "),n("p",[t._v("LDK fully implements the Lightning protocol as a highly modular Rust library. LDK's flexibility allows developers to integrate Lightning functionality into "),n("a",{attrs:{href:"https://lightningdevkit.org/case-studies/",target:"_blank",rel:"noopener noreferrer"}},[t._v("many types of applications"),n("OutboundLink")],1),t._v(", including those with pre-existing infrastructure or complex architectures. The public API comprises more than 900 exposed methods, letting users adjust and interact with protocol layers in great detail. While this customization is great for builders, it often comes with the added cost of increased complexity.")]),t._v(" "),n("p",[t._v("LDK provides sane defaults where possible. However, correctly and effectively setting up all interconnected modules requires a deeper understanding of protocol fundamentals and some familiarity with the LDK API. Moreover, because LDK adheres to the separation-of-concerns principle, it is wallet-agnostic and deliberately doesn't come with an included on-chain wallet. Therefore, the integration with a suitable on-chain wallet is left to the user.")]),t._v(" "),n("p",[t._v("As a result, it can take a bit of effort to get started with LDK. That's why we created LDK Node, a more fully-baked solution.")]),t._v(" "),n("h2",{attrs:{id:"ldk-node-simplifying-self-custodial-lightning-integration"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-simplifying-self-custodial-lightning-integration"}},[t._v("#")]),t._v(" LDK Node: Simplifying Self-custodial Lightning Integration")]),t._v(" "),n("p",[t._v("LDK Node was designed to hide protocol complexities without infringing on usability. LDK Node's much smaller API surface makes its reduced complexity evident. Compared to LDK's above 900 exposed methods, LDK Node's API currently only encompasses around 30 API calls. While simplicity and minimalism are at its core, LDK Node remains configurable enough to operate a fully functional self-custodial Lightning node in various use cases.")]),t._v(" "),n("p",[t._v("There is a trade-off between simplicity and expressiveness when designing an API while handling protocol complexity. The API needs to become more complicated to increase configurability and the interconnectivity of components. As a result, the user must spend more time examining, learning, and scrutinizing the API before finally being able to use it. While the LDK API errs on the side of expressiveness, LDK Node leans towards simplicity.")]),t._v(" "),n("p",[t._v("This first release of LDK Node comes with an opinionated set of design choices and ready-to-go modules:")]),t._v(" "),n("ul",[n("li",[t._v("The integrated "),n("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),n("OutboundLink")],1),t._v(" wallet handles on-chain data.")]),t._v(" "),n("li",[t._v("Chain data is sourced from an "),n("a",{attrs:{href:"https://github.com/Blockstream/esplora",target:"_blank",rel:"noopener noreferrer"}},[t._v("Esplora"),n("OutboundLink")],1),t._v(" server, while support for Electrum and "),n("code",[t._v("bitcoind")]),t._v(" RPC will follow soon.")]),t._v(" "),n("li",[t._v("Wallet and channel state may be persisted to an "),n("a",{attrs:{href:"https://sqlite.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SQLite"),n("OutboundLink")],1),t._v(" database, to file system, or to a custom back-end to be implemented by the user. Support for "),n("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[t._v("Versioned Storage Service (VSS)"),n("OutboundLink")],1),t._v(" will follow soon.")]),t._v(" "),n("li",[t._v("Gossip data may be sourced via Lightning's peer-to-peer network or the "),n("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/0.0.115/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rapid Gossip Sync (RGS)"),n("OutboundLink")],1),t._v(" protocol.")]),t._v(" "),n("li",[t._v("Entropy for Lightning and on-chain wallets may be sourced from raw bytes or a "),n("a",{attrs:{href:"https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki",target:"_blank",rel:"noopener noreferrer"}},[t._v("BIP39"),n("OutboundLink")],1),t._v(" mnemonic. In addition, LDK Node offers the means to generate and persist the entropy bytes to disk.")])]),t._v(" "),n("h2",{attrs:{id:"mobile-first-self-custody"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#mobile-first-self-custody"}},[t._v("#")]),t._v(" Mobile-first Self-Custody")]),t._v(" "),n("p",[t._v("The main goal of the Lightning protocol is to enable fast, private, and secure Bitcoin transactions for the end-user. However, today most Lightning deployments are custodial services that may only be queried by the client device in the end-user's hands. This is understandable: deploying self-custodial Lightning nodes on end-user devices can take a lot of work to get right, as there are many pitfalls to avoid.")]),t._v(" "),n("p",[t._v("To this end, one of the primary goals of LDK Node is to simplify the integration of self-custodial Lightning nodes in mobile applications. The features of the initial release are centered around mobile deployments. The integration with an Esplora chain data source and a Rapid Gossip Sync server allows the node to operate in mobile environments that may be limited in terms of bandwidth and overall traffic quota.")]),t._v(" "),n("p",[t._v("LDK Node itself is written in "),n("a",{attrs:{href:"https://www.rust-lang.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust"),n("OutboundLink")],1),t._v(" and may therefore be natively added as a library dependency to any "),n("code",[t._v("std")]),t._v(" Rust program. However, beyond its Rust API, it offers "),n("a",{attrs:{href:"https://www.swift.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Swift"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://kotlinlang.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kotlin"),n("OutboundLink")],1),t._v(", and "),n("a",{attrs:{href:"https://www.python.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Python"),n("OutboundLink")],1),t._v(" language bindings based on "),n("a",{attrs:{href:"https://github.com/mozilla/uniffi-rs/",target:"_blank",rel:"noopener noreferrer"}},[t._v("UniFFI"),n("OutboundLink")],1),t._v(". Moreover, "),n("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-flutter",target:"_blank",rel:"noopener noreferrer"}},[t._v("Flutter"),n("OutboundLink")],1),t._v(" bindings are also available to allow usage of the LDK Node library in mobile environments.")]),t._v(" "),n("h2",{attrs:{id:"getting-started"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting Started")]),t._v(" "),n("p",[t._v("The primary abstraction of the library is the "),n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/struct.Node.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Node")]),n("OutboundLink")],1),t._v(", which can be retrieved by setting up and configuring a "),n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/struct.Builder.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Builder")]),n("OutboundLink")],1),t._v(" to your liking and calling one of the "),n("code",[t._v("build")]),t._v(" methods. "),n("code",[t._v("Node")]),t._v(" can then be controlled via commands such as "),n("code",[t._v("start")]),t._v(", "),n("code",[t._v("stop")]),t._v(", "),n("code",[t._v("connect_open_channel")]),t._v(", "),n("code",[t._v("send_payment")]),t._v(", etc.")]),t._v(" "),n("p",[n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Read Full API Documentation"),n("OutboundLink")],1)]),t._v(" "),n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetAddress")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning_invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("secp256k1"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FromStr")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_esplora_server")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://blockstream.info/testnet/api"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tbuilder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_gossip_source_rgs")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://rapidsync.lightningdevkit.org/testnet/snapshot"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" builder"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" funding_address "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_onchain_address")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// .. fund address ..")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node_id "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"NODE_ID"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node_addr "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetAddress")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"IP_ADDR:PORT"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect_open_channel")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" node_addr"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("10000")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("wait_next_event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EVENT: {:?}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("event_handled")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INVOICE_STR"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\tnode"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("stop")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("h2",{attrs:{id:"outlook"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#outlook"}},[t._v("#")]),t._v(" Outlook")]),t._v(" "),n("p",[t._v("The 0.1 release is only the beginning for LDK Node. Development for the next release has already started, and we'll be looking to add support for sourcing chain data from Electrum or "),n("code",[t._v("bitcoind")]),t._v(" RPC, and supporting persistence to a "),n("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[t._v("VSS"),n("OutboundLink")],1),t._v(" backend (see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/issues/107",target:"_blank",rel:"noopener noreferrer"}},[t._v("v0.2 tracking issue"),n("OutboundLink")],1),t._v("). Additionally, integration with the "),n("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSP specification"),n("OutboundLink")],1),t._v(" is actively being worked on (see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-lsp-client",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSP Client"),n("OutboundLink")],1),t._v(" repository) and will come to LDK Node as soon as it's ready. Beyond these planned feature updates to the LDK Node library, we're also considering further deployment targets, including adding server-grade modules in the future.")]),t._v(" "),n("h2",{attrs:{id:"further-resources"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#further-resources"}},[t._v("#")]),t._v(" Further Resources")]),t._v(" "),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github Repository"),n("OutboundLink")],1)]),t._v(" "),n("li",[n("a",{attrs:{href:"https://docs.rs/ldk-node/*/ldk_node/",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Documentation"),n("OutboundLink")],1)]),t._v(" "),n("li",[n("a",{attrs:{href:"https://crates.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Crate"),n("OutboundLink")],1)])]),t._v(" "),n("h2",{attrs:{id:"showcases"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#showcases"}},[t._v("#")]),t._v(" Showcases")]),t._v(" "),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/reez/Monday",target:"_blank",rel:"noopener noreferrer"}},[t._v("Monday Wallet: Example wallet built with on LDK Node Swift bindings"),n("OutboundLink")],1)])])])}),[],!1,null,null,null);n.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/33.31704607.js b/assets/js/33.7c5a1a6f.js similarity index 99% rename from assets/js/33.31704607.js rename to assets/js/33.7c5a1a6f.js index 947af7df8..68db1cb29 100644 --- a/assets/js/33.31704607.js +++ b/assets/js/33.7c5a1a6f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{395:function(e,t,n){"use strict";n.r(t);var i=n(7),r=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("We are excited to release our first blog post, we have a lot to share and a lot to build. We’ll be updating this blog regularly with what we’re working on, new features and the details on new releases.")]),e._v(" "),t("h2",{attrs:{id:"ldwho"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldwho"}},[e._v("#")]),e._v(" LDWho?")]),e._v(" "),t("p",[e._v("If you’re reading this, you probably know something about the Lightning Development Kit, the easy-to-use open-source tool that simplifies how developers add highly secure, privacy-preserving Lightning functionality to bitcoin applications. What you might not know is how it got started.")]),e._v(" "),t("p",[e._v("LDK began as a side project developed by Matt Corallo "),t("a",{attrs:{href:"https://twitter.com/TheBlueMatt",target:"_blank",rel:"noopener noreferrer"}},[e._v("@TheBlueMatt"),t("OutboundLink")],1),e._v(" in "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/commit/6185a2819090bd077954244c5e2adaab5efcaa1a",target:"_blank",rel:"noopener noreferrer"}},[e._v("2018"),t("OutboundLink")],1),e._v(" called rust-lightning. One of Matt’s earliest rust-lightning "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=bfAz0vYlDAI",target:"_blank",rel:"noopener noreferrer"}},[e._v("demos"),t("OutboundLink")],1),e._v(" shows how you can take a full Lightning implementation (managing channels, generating messages to send to peers, signatures, on-chain punishment, etc), and use it to create a library with high-level APIs, so developers can build more and agonize less.")]),e._v(" "),t("p",[e._v("This highly specialized library needed to be flexible enough to let developers customize areas like on-chain wallet creation, sourcing blockchain data, and backing up channel states while paving the way for them to make those critical decisions at 10x speed.")]),e._v(" "),t("p",[e._v("Initially supported by "),t("a",{attrs:{href:"https://chaincode.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Chaincode Labs"),t("OutboundLink")],1),e._v(" and then by "),t("a",{attrs:{href:"https://spiral.xyz/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spiral"),t("OutboundLink")],1),e._v(", LDK has gone from a good idea to a mature, "),t("a",{attrs:{href:"https://github.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("open-source project"),t("OutboundLink")],1),e._v(" with "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/graphs/contributors",target:"_blank",rel:"noopener noreferrer"}},[e._v("many contributors"),t("OutboundLink")],1),e._v(" in just a few years. LDK is a robust, modular, mobile-friendly SDK that can be "),t("a",{attrs:{href:"https://vimeo.com/showcase/8372504/video/412818125",target:"_blank",rel:"noopener noreferrer"}},[e._v("integrated into existing bitcoin wallets"),t("OutboundLink")],1),e._v(" while significantly "),t("a",{attrs:{href:"https://bitcointv.com/w/sy6s9vVCmDvXr46YtbYcXM",target:"_blank",rel:"noopener noreferrer"}},[e._v("improving how developers integrate Lightning"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("Over time, we hope that LDK will become a public good that doesn’t rely on a single entity like Spiral to be sustainable, which is why we’re already fostering a community, empowering non-Spiral participants, and "),t("a",{attrs:{href:"https://spiral.xyz/blog/a-framework-for-sustainable-open-source-bitcoin-development/",target:"_blank",rel:"noopener noreferrer"}},[e._v("gradually reducing Spiral’s influence"),t("OutboundLink")],1),e._v(". Like Bitcoin Core, we expect LDK to have a strong group of volunteers contributing to the project and many entities funding the project.")]),e._v(" "),t("h2",{attrs:{id:"what-advantages-does-ldk-offer-developers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-advantages-does-ldk-offer-developers"}},[e._v("#")]),e._v(" What advantages does LDK offer developers?")]),e._v(" "),t("p",[e._v("Before committing to LDK, we spoke with over 50 wallet developers to learn what challenges they faced. We learned that developing Lightning apps was a universally bad experience, especially in mobile environments, and that a small team of experienced engineers could take up to two years to build a basic Lightning application. So… not great.")]),e._v(" "),t("p",[e._v("LDK is a flexible Lightning implementation that focuses on running the Lightning node on a mobile phone in a non-custodial manner, which has significant privacy and sovereignty benefits. While this presents some technical challenges, non-custodial mobile apps are where LDK specializes, whether someone is building a wallet from scratch or integrating LDK into one that already exists.")]),e._v(" "),t("p",[e._v("Before LDK, if your team wanted to add Lightning functionality to a mobile app, you most likely had to modify and customize an existing implementation like LND to make it suitable for mobile devices. Core Lightning is also hard to run on iPhones. Both of these implementations are out-of-the-box node solutions that provide solid RPC and HTTP interfaces, but are targeted for server environments or simply aren’t suited to mobile.")]),e._v(" "),t("p",[e._v("Furthermore, if you want to turn your on-chain wallet into a unified wallet experience or source chain data from a third-party server using the Electrum protocol for resource-constrained devices, it’s complex, time-consuming, and a huge engineering undertaking.")]),e._v(" "),t("p",[e._v("Maintaining an LN implementation that you can trust with real money is challenging, and different needs exist for routing nodes and mobile nodes. Maintenance costs also increase over time due to ageing codebases, interactions with other layers, and new use cases with different performance and security trade-offs. We see this with "),t("a",{attrs:{href:"https://github.com/breez/breezmobile",target:"_blank",rel:"noopener noreferrer"}},[e._v("Breez"),t("OutboundLink")],1),e._v(" forking "),t("a",{attrs:{href:"https://github.com/breez/lnd",target:"_blank",rel:"noopener noreferrer"}},[e._v("LND"),t("OutboundLink")],1),e._v(" to make it suitable for mobile and ACINQ doing something similar with "),t("a",{attrs:{href:"https://github.com/ACINQ/phoenix",target:"_blank",rel:"noopener noreferrer"}},[e._v("Phoenix"),t("OutboundLink")],1),e._v(" wallet and "),t("a",{attrs:{href:"https://github.com/ACINQ/lightning-kmp",target:"_blank",rel:"noopener noreferrer"}},[e._v("lightning-kmp"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("We created LDK in multiple languages with an API-first approach designed to run at the application layer, like Rust’s "),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Persist"),t("OutboundLink")],1),e._v(" trait. Persist defines behaviour for persisting channel states but lets you specify whether you write this data to disk or another backup mechanism, such as the cloud. You don’t need to write an LN implementation from scratch or modify an existing one to use LN functionality. Just call our APIs from your app.")]),e._v(" "),t("p",[e._v("Finally (for this section), LDK’s flexibility enables several different architectures without sacrificing security. Its lightweight design can be optimized to run on embedded devices or HSMs (hardware security modules) and it doesn’t make system calls, so it can run in almost any OS environment. For example, you can opt to run some Lightning logic, such as signing transactions and updating channel states on an HSM that has specific "),t("a",{attrs:{href:"https://gitlab.com/lightning-signer/docs/-/blob/master/README.md",target:"_blank",rel:"noopener noreferrer"}},[e._v("spending policies"),t("OutboundLink")],1),e._v(" and manages private keys. Then you connect it to a server with its own TCP/IP stack using a serial communication method such as USB.")]),e._v(" "),t("p",[e._v("Check out this "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=9-81tobFSKg",target:"_blank",rel:"noopener noreferrer"}},[e._v("presentation"),t("OutboundLink")],1),e._v(" at btc++ by "),t("a",{attrs:{href:"https://twitter.com/jkczyz",target:"_blank",rel:"noopener noreferrer"}},[e._v("Jeff Czyz"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://twitter.com/arikaleph",target:"_blank",rel:"noopener noreferrer"}},[e._v("Arik Sosman"),t("OutboundLink")],1),e._v(" to learn more about LDK "),t("a",{attrs:{href:"https://lightningdevkit.org/introduction/use_cases/",target:"_blank",rel:"noopener noreferrer"}},[e._v("use cases"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"who-uses-ldk"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#who-uses-ldk"}},[e._v("#")]),e._v(" Who uses LDK?")]),e._v(" "),t("p",[e._v("LDK supports applications that require running many nodes (such as server/custodial apps), letting users run nodes on mobile devices, integrating with existing infrastructure, broad customization options, and resource-constrained embedded systems such as point of sale, IoT, and so on and so on, etc.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://bluewallet.io",target:"_blank",rel:"noopener noreferrer"}},[e._v("Blue Wallet"),t("OutboundLink")],1),e._v(" was LDK’s patient zero and ideal first adopter since it is both non-custodial and mobile. Their team maintains "),t("a",{attrs:{href:"https://github.com/BlueWallet/rn-ldk",target:"_blank",rel:"noopener noreferrer"}},[e._v("rn-ldk"),t("OutboundLink")],1),e._v(" and runs it on both Android and iOS.The wallet is likely to ship with LDK soon but not before some critical infrastructure is in place. While non-custodial mobile wallets are LDK’s primary use case, that doesn’t make it limited to them.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://cash.app",target:"_blank",rel:"noopener noreferrer"}},[e._v("CashApp"),t("OutboundLink")],1),e._v(", one of the world’s most used payment apps, chose LDK for its Lightning implementation because of its customizability. While custodial server-based solutions are not the primary use case for LDK, it shows how adaptable the library is. Ryan Loomba recently explained some of the trade-offs their team had to think about when comparing LDK to other solutions "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=kbhL5RqL8Aw",target:"_blank",rel:"noopener noreferrer"}},[e._v("at btc++"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://l2.technology/sensei",target:"_blank",rel:"noopener noreferrer"}},[e._v("Sensei"),t("OutboundLink")],1),e._v(", an out-of-the-box lightning node solution, is also powered by LDK. Its modular architecture enables a unique multi-node operation mode, letting nodes easily share a network graph, route scoring, and chain data which enables exciting new use cases.")]),e._v(" "),t("p",[e._v("We’re also talking to dozens of developers, some of whom we expect to adopt LDK soon.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions/1554",target:"_blank",rel:"noopener noreferrer"}},[e._v("Know someone building a Lightning wallet or related application?"),t("OutboundLink")],1),e._v(" Point them in "),t("a",{attrs:{href:"https://twitter.com/moneyball",target:"_blank",rel:"noopener noreferrer"}},[e._v("@moneyball’s"),t("OutboundLink")],1),e._v(" direction. If you’re already using LDK and have questions, hop into our "),t("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discord"),t("OutboundLink")],1),e._v(" or checkout GitHub "),t("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discussions"),t("OutboundLink")],1)]),e._v(" "),t("h2",{attrs:{id:"what-are-ldk-s-engineering-priorities"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-are-ldk-s-engineering-priorities"}},[e._v("#")]),e._v(" What are LDK’s engineering priorities?")]),e._v(" "),t("p",[t("code",[e._v("Offline Receive")]),t("br"),e._v("\nA problem with Lightning UX is that mobile wallets can’t receive payments unless the user is using the app. We’re developing solutions in conjunction with the LN developer community that will let offline nodes receive payments. Spiral’s Matt Corallo has a "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("pull request"),t("OutboundLink")],1),e._v(" open that proposes a protocol to fix this exact problem. It includes his original post to the Lightning Devs mailing list which is a "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("pretty good technical"),t("OutboundLink")],1),e._v(" read on this issue if you’re in the mood for one of those.")]),e._v(" "),t("p",[t("code",[e._v("BOLT 12")]),t("br"),e._v("\nThis feature improves privacy by allowing reusable payments over blinded paths and provides a framework for future upgrades that support recurring payments. There’s still work to be done, and it includes implementing route blinding/blinded paths, an onion messages API for requesting invoices, and BOLT 12 invoice parsing.")]),e._v(" "),t("p",[t("code",[e._v("Taproot")]),t("br"),e._v("\nTaproot! People love it. We love it. It’s been several months since full activation, and LDK will start to take advantage of everything it offers. This includes improved on-chain privacy by making current funding channel outputs (2-of-2 multisig) indistinguishable from single sig outputs, and making channel opening and closing transactions look more like regular non-lightning transactions. In addition, we’re looking to support multi-sig channel capabilities as they allow for greater security, redundancy, and flexibility.")]),e._v(" "),t("p",[t("code",[e._v("Language Bindings")]),t("br"),e._v("\nWe’re making existing language integrations feel more native. We currently support Rust, C/C++, Swift, Java, & Kotlin. It’s now in the beta stage, but "),t("a",{attrs:{href:"https://www.npmjs.com/package/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("JavaScript/TypeScript/Wasm"),t("OutboundLink")],1),e._v(" is also supported, and we are prioritizing bug fixing for early adopters. In the future, expect support for C#, Python, Flutter/Dart, and possibly others.")]),e._v(" "),t("p",[e._v("Also in LDK’s future: a simplified API that makes opinionated decisions on behalf of developers that will accelerate getting their apps up and running. Think of it as a Rust crate but using UniFFI to auto-generate language bindings for Kotlin, Swift, Python, and Ruby that expedite basic send/receive functionality.")]),e._v(" "),t("h2",{attrs:{id:"notable-updates"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#notable-updates"}},[e._v("#")]),e._v(" Notable Updates")]),e._v(" "),t("p",[e._v("Phantom Node support is up and running (separate blog post coming soon…ish). This integration adds support for multi-node receive, which enables enterprise-level architecture. This is important since users might need production nodes to receive payments when load balancing is required.")]),e._v(" "),t("p",[e._v("We've introduced a new client-side pathfinding API to LDK that simplifies quickly downloading gossip data from a server. This means that servers can't know who you are paying or how much.")]),e._v(" "),t("p",[e._v("We now support zero conf channels, allowing immediate forwarding of payments after channel opening/receiving for those wanting to build inbound liquidity services.")]),e._v(" "),t("p",[e._v("SCID Aliases (short channel IDs) were added in a recent release and may be negotiated when opening a channel with a peer. This has significant privacy benefits and will likely be the default in the future.")]),e._v(" "),t("p",[e._v("Anything else?")]),e._v(" "),t("p",[e._v("Absolutely. But this post is long enough for now. Keep an eye out for announcements from "),t("a",{attrs:{href:"https://twitter.com/spiralbtc",target:"_blank",rel:"noopener noreferrer"}},[e._v("@spiralbtc"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://twitter.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("@lightningdevkit"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{393:function(e,t,n){"use strict";n.r(t);var i=n(7),r=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("We are excited to release our first blog post, we have a lot to share and a lot to build. We’ll be updating this blog regularly with what we’re working on, new features and the details on new releases.")]),e._v(" "),t("h2",{attrs:{id:"ldwho"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldwho"}},[e._v("#")]),e._v(" LDWho?")]),e._v(" "),t("p",[e._v("If you’re reading this, you probably know something about the Lightning Development Kit, the easy-to-use open-source tool that simplifies how developers add highly secure, privacy-preserving Lightning functionality to bitcoin applications. What you might not know is how it got started.")]),e._v(" "),t("p",[e._v("LDK began as a side project developed by Matt Corallo "),t("a",{attrs:{href:"https://twitter.com/TheBlueMatt",target:"_blank",rel:"noopener noreferrer"}},[e._v("@TheBlueMatt"),t("OutboundLink")],1),e._v(" in "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/commit/6185a2819090bd077954244c5e2adaab5efcaa1a",target:"_blank",rel:"noopener noreferrer"}},[e._v("2018"),t("OutboundLink")],1),e._v(" called rust-lightning. One of Matt’s earliest rust-lightning "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=bfAz0vYlDAI",target:"_blank",rel:"noopener noreferrer"}},[e._v("demos"),t("OutboundLink")],1),e._v(" shows how you can take a full Lightning implementation (managing channels, generating messages to send to peers, signatures, on-chain punishment, etc), and use it to create a library with high-level APIs, so developers can build more and agonize less.")]),e._v(" "),t("p",[e._v("This highly specialized library needed to be flexible enough to let developers customize areas like on-chain wallet creation, sourcing blockchain data, and backing up channel states while paving the way for them to make those critical decisions at 10x speed.")]),e._v(" "),t("p",[e._v("Initially supported by "),t("a",{attrs:{href:"https://chaincode.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Chaincode Labs"),t("OutboundLink")],1),e._v(" and then by "),t("a",{attrs:{href:"https://spiral.xyz/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spiral"),t("OutboundLink")],1),e._v(", LDK has gone from a good idea to a mature, "),t("a",{attrs:{href:"https://github.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("open-source project"),t("OutboundLink")],1),e._v(" with "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/graphs/contributors",target:"_blank",rel:"noopener noreferrer"}},[e._v("many contributors"),t("OutboundLink")],1),e._v(" in just a few years. LDK is a robust, modular, mobile-friendly SDK that can be "),t("a",{attrs:{href:"https://vimeo.com/showcase/8372504/video/412818125",target:"_blank",rel:"noopener noreferrer"}},[e._v("integrated into existing bitcoin wallets"),t("OutboundLink")],1),e._v(" while significantly "),t("a",{attrs:{href:"https://bitcointv.com/w/sy6s9vVCmDvXr46YtbYcXM",target:"_blank",rel:"noopener noreferrer"}},[e._v("improving how developers integrate Lightning"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("Over time, we hope that LDK will become a public good that doesn’t rely on a single entity like Spiral to be sustainable, which is why we’re already fostering a community, empowering non-Spiral participants, and "),t("a",{attrs:{href:"https://spiral.xyz/blog/a-framework-for-sustainable-open-source-bitcoin-development/",target:"_blank",rel:"noopener noreferrer"}},[e._v("gradually reducing Spiral’s influence"),t("OutboundLink")],1),e._v(". Like Bitcoin Core, we expect LDK to have a strong group of volunteers contributing to the project and many entities funding the project.")]),e._v(" "),t("h2",{attrs:{id:"what-advantages-does-ldk-offer-developers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-advantages-does-ldk-offer-developers"}},[e._v("#")]),e._v(" What advantages does LDK offer developers?")]),e._v(" "),t("p",[e._v("Before committing to LDK, we spoke with over 50 wallet developers to learn what challenges they faced. We learned that developing Lightning apps was a universally bad experience, especially in mobile environments, and that a small team of experienced engineers could take up to two years to build a basic Lightning application. So… not great.")]),e._v(" "),t("p",[e._v("LDK is a flexible Lightning implementation that focuses on running the Lightning node on a mobile phone in a non-custodial manner, which has significant privacy and sovereignty benefits. While this presents some technical challenges, non-custodial mobile apps are where LDK specializes, whether someone is building a wallet from scratch or integrating LDK into one that already exists.")]),e._v(" "),t("p",[e._v("Before LDK, if your team wanted to add Lightning functionality to a mobile app, you most likely had to modify and customize an existing implementation like LND to make it suitable for mobile devices. Core Lightning is also hard to run on iPhones. Both of these implementations are out-of-the-box node solutions that provide solid RPC and HTTP interfaces, but are targeted for server environments or simply aren’t suited to mobile.")]),e._v(" "),t("p",[e._v("Furthermore, if you want to turn your on-chain wallet into a unified wallet experience or source chain data from a third-party server using the Electrum protocol for resource-constrained devices, it’s complex, time-consuming, and a huge engineering undertaking.")]),e._v(" "),t("p",[e._v("Maintaining an LN implementation that you can trust with real money is challenging, and different needs exist for routing nodes and mobile nodes. Maintenance costs also increase over time due to ageing codebases, interactions with other layers, and new use cases with different performance and security trade-offs. We see this with "),t("a",{attrs:{href:"https://github.com/breez/breezmobile",target:"_blank",rel:"noopener noreferrer"}},[e._v("Breez"),t("OutboundLink")],1),e._v(" forking "),t("a",{attrs:{href:"https://github.com/breez/lnd",target:"_blank",rel:"noopener noreferrer"}},[e._v("LND"),t("OutboundLink")],1),e._v(" to make it suitable for mobile and ACINQ doing something similar with "),t("a",{attrs:{href:"https://github.com/ACINQ/phoenix",target:"_blank",rel:"noopener noreferrer"}},[e._v("Phoenix"),t("OutboundLink")],1),e._v(" wallet and "),t("a",{attrs:{href:"https://github.com/ACINQ/lightning-kmp",target:"_blank",rel:"noopener noreferrer"}},[e._v("lightning-kmp"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("We created LDK in multiple languages with an API-first approach designed to run at the application layer, like Rust’s "),t("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Persist"),t("OutboundLink")],1),e._v(" trait. Persist defines behaviour for persisting channel states but lets you specify whether you write this data to disk or another backup mechanism, such as the cloud. You don’t need to write an LN implementation from scratch or modify an existing one to use LN functionality. Just call our APIs from your app.")]),e._v(" "),t("p",[e._v("Finally (for this section), LDK’s flexibility enables several different architectures without sacrificing security. Its lightweight design can be optimized to run on embedded devices or HSMs (hardware security modules) and it doesn’t make system calls, so it can run in almost any OS environment. For example, you can opt to run some Lightning logic, such as signing transactions and updating channel states on an HSM that has specific "),t("a",{attrs:{href:"https://gitlab.com/lightning-signer/docs/-/blob/master/README.md",target:"_blank",rel:"noopener noreferrer"}},[e._v("spending policies"),t("OutboundLink")],1),e._v(" and manages private keys. Then you connect it to a server with its own TCP/IP stack using a serial communication method such as USB.")]),e._v(" "),t("p",[e._v("Check out this "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=9-81tobFSKg",target:"_blank",rel:"noopener noreferrer"}},[e._v("presentation"),t("OutboundLink")],1),e._v(" at btc++ by "),t("a",{attrs:{href:"https://twitter.com/jkczyz",target:"_blank",rel:"noopener noreferrer"}},[e._v("Jeff Czyz"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://twitter.com/arikaleph",target:"_blank",rel:"noopener noreferrer"}},[e._v("Arik Sosman"),t("OutboundLink")],1),e._v(" to learn more about LDK "),t("a",{attrs:{href:"https://lightningdevkit.org/introduction/use_cases/",target:"_blank",rel:"noopener noreferrer"}},[e._v("use cases"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h2",{attrs:{id:"who-uses-ldk"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#who-uses-ldk"}},[e._v("#")]),e._v(" Who uses LDK?")]),e._v(" "),t("p",[e._v("LDK supports applications that require running many nodes (such as server/custodial apps), letting users run nodes on mobile devices, integrating with existing infrastructure, broad customization options, and resource-constrained embedded systems such as point of sale, IoT, and so on and so on, etc.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://bluewallet.io",target:"_blank",rel:"noopener noreferrer"}},[e._v("Blue Wallet"),t("OutboundLink")],1),e._v(" was LDK’s patient zero and ideal first adopter since it is both non-custodial and mobile. Their team maintains "),t("a",{attrs:{href:"https://github.com/BlueWallet/rn-ldk",target:"_blank",rel:"noopener noreferrer"}},[e._v("rn-ldk"),t("OutboundLink")],1),e._v(" and runs it on both Android and iOS.The wallet is likely to ship with LDK soon but not before some critical infrastructure is in place. While non-custodial mobile wallets are LDK’s primary use case, that doesn’t make it limited to them.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://cash.app",target:"_blank",rel:"noopener noreferrer"}},[e._v("CashApp"),t("OutboundLink")],1),e._v(", one of the world’s most used payment apps, chose LDK for its Lightning implementation because of its customizability. While custodial server-based solutions are not the primary use case for LDK, it shows how adaptable the library is. Ryan Loomba recently explained some of the trade-offs their team had to think about when comparing LDK to other solutions "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=kbhL5RqL8Aw",target:"_blank",rel:"noopener noreferrer"}},[e._v("at btc++"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://l2.technology/sensei",target:"_blank",rel:"noopener noreferrer"}},[e._v("Sensei"),t("OutboundLink")],1),e._v(", an out-of-the-box lightning node solution, is also powered by LDK. Its modular architecture enables a unique multi-node operation mode, letting nodes easily share a network graph, route scoring, and chain data which enables exciting new use cases.")]),e._v(" "),t("p",[e._v("We’re also talking to dozens of developers, some of whom we expect to adopt LDK soon.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions/1554",target:"_blank",rel:"noopener noreferrer"}},[e._v("Know someone building a Lightning wallet or related application?"),t("OutboundLink")],1),e._v(" Point them in "),t("a",{attrs:{href:"https://twitter.com/moneyball",target:"_blank",rel:"noopener noreferrer"}},[e._v("@moneyball’s"),t("OutboundLink")],1),e._v(" direction. If you’re already using LDK and have questions, hop into our "),t("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discord"),t("OutboundLink")],1),e._v(" or checkout GitHub "),t("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discussions"),t("OutboundLink")],1)]),e._v(" "),t("h2",{attrs:{id:"what-are-ldk-s-engineering-priorities"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-are-ldk-s-engineering-priorities"}},[e._v("#")]),e._v(" What are LDK’s engineering priorities?")]),e._v(" "),t("p",[t("code",[e._v("Offline Receive")]),t("br"),e._v("\nA problem with Lightning UX is that mobile wallets can’t receive payments unless the user is using the app. We’re developing solutions in conjunction with the LN developer community that will let offline nodes receive payments. Spiral’s Matt Corallo has a "),t("a",{attrs:{href:"https://github.com/lightning/bolts/pull/989",target:"_blank",rel:"noopener noreferrer"}},[e._v("pull request"),t("OutboundLink")],1),e._v(" open that proposes a protocol to fix this exact problem. It includes his original post to the Lightning Devs mailing list which is a "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("pretty good technical"),t("OutboundLink")],1),e._v(" read on this issue if you’re in the mood for one of those.")]),e._v(" "),t("p",[t("code",[e._v("BOLT 12")]),t("br"),e._v("\nThis feature improves privacy by allowing reusable payments over blinded paths and provides a framework for future upgrades that support recurring payments. There’s still work to be done, and it includes implementing route blinding/blinded paths, an onion messages API for requesting invoices, and BOLT 12 invoice parsing.")]),e._v(" "),t("p",[t("code",[e._v("Taproot")]),t("br"),e._v("\nTaproot! People love it. We love it. It’s been several months since full activation, and LDK will start to take advantage of everything it offers. This includes improved on-chain privacy by making current funding channel outputs (2-of-2 multisig) indistinguishable from single sig outputs, and making channel opening and closing transactions look more like regular non-lightning transactions. In addition, we’re looking to support multi-sig channel capabilities as they allow for greater security, redundancy, and flexibility.")]),e._v(" "),t("p",[t("code",[e._v("Language Bindings")]),t("br"),e._v("\nWe’re making existing language integrations feel more native. We currently support Rust, C/C++, Swift, Java, & Kotlin. It’s now in the beta stage, but "),t("a",{attrs:{href:"https://www.npmjs.com/package/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("JavaScript/TypeScript/Wasm"),t("OutboundLink")],1),e._v(" is also supported, and we are prioritizing bug fixing for early adopters. In the future, expect support for C#, Python, Flutter/Dart, and possibly others.")]),e._v(" "),t("p",[e._v("Also in LDK’s future: a simplified API that makes opinionated decisions on behalf of developers that will accelerate getting their apps up and running. Think of it as a Rust crate but using UniFFI to auto-generate language bindings for Kotlin, Swift, Python, and Ruby that expedite basic send/receive functionality.")]),e._v(" "),t("h2",{attrs:{id:"notable-updates"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#notable-updates"}},[e._v("#")]),e._v(" Notable Updates")]),e._v(" "),t("p",[e._v("Phantom Node support is up and running (separate blog post coming soon…ish). This integration adds support for multi-node receive, which enables enterprise-level architecture. This is important since users might need production nodes to receive payments when load balancing is required.")]),e._v(" "),t("p",[e._v("We've introduced a new client-side pathfinding API to LDK that simplifies quickly downloading gossip data from a server. This means that servers can't know who you are paying or how much.")]),e._v(" "),t("p",[e._v("We now support zero conf channels, allowing immediate forwarding of payments after channel opening/receiving for those wanting to build inbound liquidity services.")]),e._v(" "),t("p",[e._v("SCID Aliases (short channel IDs) were added in a recent release and may be negotiated when opening a channel with a peer. This has significant privacy benefits and will likely be the default in the future.")]),e._v(" "),t("p",[e._v("Anything else?")]),e._v(" "),t("p",[e._v("Absolutely. But this post is long enough for now. Keep an eye out for announcements from "),t("a",{attrs:{href:"https://twitter.com/spiralbtc",target:"_blank",rel:"noopener noreferrer"}},[e._v("@spiralbtc"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://twitter.com/lightningdevkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("@lightningdevkit"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/34.ec904560.js b/assets/js/34.5121b9d8.js similarity index 98% rename from assets/js/34.ec904560.js rename to assets/js/34.5121b9d8.js index 31decabd0..e771b6e25 100644 --- a/assets/js/34.ec904560.js +++ b/assets/js/34.5121b9d8.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{397:function(e,t,n){"use strict";n.r(t);var i=n(7),a=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Mutiny is a new lightning wallet for the web. It is the first self-custodial wallet to run directly in a user's browser. It’s built on top of LDK and "),t("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v(", written in Rust, and compiled into WebAssembly. It offers a simple, intuitive interface for sending and receiving payments and other advanced features, such as Nostr Wallet Connect and subscription payments.")]),e._v(" "),t("p",[e._v("We chose to build on LDK and BDK because it wouldn’t have been possible to build a wallet like Mutiny in any other way. Since LDK is written in Rust, we were able to compile it into WebAssembly. Rust's unique combination of type-safety, memory-safety, and efficient runtime performance make it ideally suited to a lightning node that must be reliable, fast, and lightweight enough to run on a mobile phone. LDK's modular design means we can customize it to work within the specific constraints of a web browser. LDK also provides a robust API for building advanced features for our wallet that would otherwise not be possible.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),t("p",[e._v("We used LDK to make a crate called mutiny-node which holds all our main wallet logic. Then we used the wasm-bindgencrate to generate JavaScript bindings that can be imported into a regular web project. Thankfully, LDK supports no_std, so compiling it into WebAssembly without any modifications was possible.")]),e._v(" "),t("p",[e._v("Mutiny is a lite-client wallet, meaning it does not run a full bitcoin node. Instead, it gets its blockchain data from an esplora instance. LDK's Filter interface made it easy to implement this, allowing for a simple and efficient way to sync the wallet with the blockchain. "),t("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/0.0.115/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rapid Gossip Sync"),t("OutboundLink")],1),e._v(" also helps make the wallet sync quickly, and RGS allows us to sync lightning gossip data nearly instantly without spending unnecessary bandwidth and CPU resources.")]),e._v(" "),t("p",[e._v("Local storage can be unreliable in web browsers, so we also want users to be able to recover their wallet in case they lose their device. We implemented the LDK project's "),t("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[e._v("VSS"),t("OutboundLink")],1),e._v(" specification to give our users encrypted cloud backups to support this.")]),e._v(" "),t("p",[e._v("While we're currently focused on the web, this architecture and the flexibility of LDK means we will be able to share most of our code with a mobile or even server version of Mutiny in the future.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("LDK made building a lightning wallet that runs in the browser possible. Compiling to WebAssembly and LDK's various tools for lite clients allowed us to create an unstoppable, self-custodial wallet that anyone can use without downloading any software. We hope that Mutiny will help bring lightning to the masses, and we are excited to see what the future holds for LDK and lightning on the web.")]),e._v(" "),t("p",[e._v("You can learn more and try it out at "),t("a",{attrs:{href:"https://www.mutinywallet.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("mutinywallet.com"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{395:function(e,t,n){"use strict";n.r(t);var i=n(7),a=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Mutiny is a new lightning wallet for the web. It is the first self-custodial wallet to run directly in a user's browser. It’s built on top of LDK and "),t("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v(", written in Rust, and compiled into WebAssembly. It offers a simple, intuitive interface for sending and receiving payments and other advanced features, such as Nostr Wallet Connect and subscription payments.")]),e._v(" "),t("p",[e._v("We chose to build on LDK and BDK because it wouldn’t have been possible to build a wallet like Mutiny in any other way. Since LDK is written in Rust, we were able to compile it into WebAssembly. Rust's unique combination of type-safety, memory-safety, and efficient runtime performance make it ideally suited to a lightning node that must be reliable, fast, and lightweight enough to run on a mobile phone. LDK's modular design means we can customize it to work within the specific constraints of a web browser. LDK also provides a robust API for building advanced features for our wallet that would otherwise not be possible.")]),e._v(" "),t("h1",{attrs:{id:"what-we-did"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-we-did"}},[e._v("#")]),e._v(" What we did?")]),e._v(" "),t("p",[e._v("We used LDK to make a crate called mutiny-node which holds all our main wallet logic. Then we used the wasm-bindgencrate to generate JavaScript bindings that can be imported into a regular web project. Thankfully, LDK supports no_std, so compiling it into WebAssembly without any modifications was possible.")]),e._v(" "),t("p",[e._v("Mutiny is a lite-client wallet, meaning it does not run a full bitcoin node. Instead, it gets its blockchain data from an esplora instance. LDK's Filter interface made it easy to implement this, allowing for a simple and efficient way to sync the wallet with the blockchain. "),t("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/0.0.115/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rapid Gossip Sync"),t("OutboundLink")],1),e._v(" also helps make the wallet sync quickly, and RGS allows us to sync lightning gossip data nearly instantly without spending unnecessary bandwidth and CPU resources.")]),e._v(" "),t("p",[e._v("Local storage can be unreliable in web browsers, so we also want users to be able to recover their wallet in case they lose their device. We implemented the LDK project's "),t("a",{attrs:{href:"https://github.com/lightningdevkit/vss-server",target:"_blank",rel:"noopener noreferrer"}},[e._v("VSS"),t("OutboundLink")],1),e._v(" specification to give our users encrypted cloud backups to support this.")]),e._v(" "),t("p",[e._v("While we're currently focused on the web, this architecture and the flexibility of LDK means we will be able to share most of our code with a mobile or even server version of Mutiny in the future.")]),e._v(" "),t("h1",{attrs:{id:"results"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),t("p",[e._v("LDK made building a lightning wallet that runs in the browser possible. Compiling to WebAssembly and LDK's various tools for lite clients allowed us to create an unstoppable, self-custodial wallet that anyone can use without downloading any software. We hope that Mutiny will help bring lightning to the masses, and we are excited to see what the future holds for LDK and lightning on the web.")]),e._v(" "),t("p",[e._v("You can learn more and try it out at "),t("a",{attrs:{href:"https://www.mutinywallet.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("mutinywallet.com"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/35.e55e23aa.js b/assets/js/35.c5b0efb1.js similarity index 99% rename from assets/js/35.e55e23aa.js rename to assets/js/35.c5b0efb1.js index fcaff0f1a..8c2764a61 100644 --- a/assets/js/35.e55e23aa.js +++ b/assets/js/35.c5b0efb1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{400:function(e,t,n){"use strict";n.r(t);var i=n(7),o=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Lightning development is tough. While going custodial simplifies the process, it means sacrificing user privacy, censorship resistance, and self-sovereignty, all of which contradict bitcoin’s ethos. Therefore, many companies and projects have started with or redirected their focus from building custodial to non-custodial Lightning applications.")]),e._v(" "),t("h2",{attrs:{id:"obstacles"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#obstacles"}},[e._v("#")]),e._v(" Obstacles")]),e._v(" "),t("p",[e._v("There are several basic requirements for wallets wanting to add Lightning capabilities, such as connecting to the Lightning Network via a Lightning Implementation, syncing with on-chain transactions, and opening and closing channels. When building a mobile application, developers face additional technical challenges:")]),e._v(" "),t("h2",{attrs:{id:"liquidity"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#liquidity"}},[e._v("#")]),e._v(" Liquidity")]),e._v(" "),t("p",[e._v("To receive funds via Lightning, someone must have on-chain bitcoin locked up in a channel. Transaction completion is delayed if the receiver has an empty or insufficient channel balance. For example, let’s say that someone has 50,000 sats of inbound liquidity and is trying to receive 100,000 sats. Before the Lightning transaction can be initiated, additional liquidity is required to cover the 100,000 sats total plus fees from channel reserves and anchor outputs, which are mechanisms to improve security. This is done via on-chain transactions, which come with fees.")]),e._v(" "),t("p",[e._v("Additionally, on-chain transactions must be mined into multiple blocks before being confirmed. It’s not a great user experience if someone has to do work upfront and wait roughly 30–60 minutes before they can send or receive money.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://lightningdevkit.org/blog/zero-confirmation-channels/",target:"_blank",rel:"noopener noreferrer"}},[e._v("0-conf"),t("OutboundLink")],1),e._v(" channels offer a partial solution, allowing users to receive Lightning instantly. 0-conf enables the client to trust their channel counterparty (usually an application vendor or partner) for a limited time until an on-chain transaction is confirmed. While this helps with speed, the fact that 0conf channels require some level of trust is a trade-off.")]),e._v(" "),t("p",[e._v("Liquidity Service Providers (LSPs) provide liquidity upfront through automated channel and liquidity management. LSPs supply more liquidity than required for immediate payments rather than the exact amount to ensure that remaining funds are in the channel for future transactions. If a user conducts multiple payments, it’s best to avoid doing on-chain transactions for every Lightning transaction.")]),e._v(" "),t("p",[e._v("LSPs do not want to pay excessive on-chain fees, but it’s hard to predict how often people will send and receive transactions and for how much. Therefore, there’s no straightforward way to know how much liquidity should be locked into a given channel. LSPs have to determine how much money they can contribute and how much it'll cost. This can be anywhere from aggressive (locking up a generous amount) to conservative (locking up a small amount). Ultimately, this decision results in a “compression ratio,\" i.e., the number of on-chain transactions required per Lightning transaction. Some very conservative LSPs may get a compression ratio close to one, saving their users relatively little on fees, but there is nearly always some gain to be had in using Lightning over on-chain.")]),e._v(" "),t("p",[e._v("While predicting what the compression ratio should be remains a major challenge, most solutions today offer some compression information, allowing us to learn and improve. For this reason, it’s worth deploying Lightning for instant transactions at lower costs compared to on-chain, even if it's not as common as it could be. We expect this to get better over time.")]),e._v(" "),t("h1",{attrs:{id:"receive-wakeup"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#receive-wakeup"}},[e._v("#")]),e._v(" Receive Wakeup")]),e._v(" "),t("p",[e._v("Lightning requires nodes (or, specifically, their cryptographic keys) to be online to exchange signatures and complete payments, meaning the user must be on their phone and with service. Receiving wakeups is problematic because incomplete payments are not great for the Lightning Network—it’s detrimental to keep the money for a payment locked up until someone comes back online.")]),e._v(" "),t("p",[e._v("iOS and Android operating systems help address this problem by allowing a small amount of code to run when notifications are received, even if the relevant application isn’t open. However, suppose an application is infrequently used or the device has a low battery. In that case, the application will often not get any CPU time, resulting in the payment being stuck until the user opens the app.")]),e._v(" "),t("p",[e._v("A lot of work must be done to make it possible for senders and recipients to exchange payments asynchronously, "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307",target:"_blank",rel:"noopener noreferrer"}},[e._v("but a protocol sketch is in the works"),t("OutboundLink")],1),e._v(". You can find a more detailed explainer "),t("a",{attrs:{href:"https://gist.github.com/remyers/e0d2bedb7bc87371d1bdbbb6fff2edd1",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h1",{attrs:{id:"live-backups"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#live-backups"}},[e._v("#")]),e._v(" Live Backups")]),e._v(" "),t("p",[e._v("These are especially problematic when a user has to reinstall an application or loses their phone. In addition to needing their seed phrase, they’ll need the latest Lightning state data stored on their device to get their money back reliably.")]),e._v(" "),t("p",[e._v("The Lightning state changes every time a user sends or receives money, so backups must be frequently updated on a server. While some devices use Google Drive or iCloud, those protocols sync asynchronously, often leading to data being out of sync. Cloud methods sanitize data stored on the client well, but they may not ensure reliable full funds recovery if a device is lost.")]),e._v(" "),t("p",[e._v("Advanced versions of live online sync allow users to open the same wallet on multiple devices. Users often do this despite it being challenging to do with Lightning applications since two devices running simultaneously can result in losing funds.")]),e._v(" "),t("h1",{attrs:{id:"privacy-preserving-payment-routing"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#privacy-preserving-payment-routing"}},[e._v("#")]),e._v(" Privacy-preserving Payment Routing")]),e._v(" "),t("p",[e._v("Another commonly discussed issue is payment routing through the Lightning Network. This isn't easy because the route finder has to have some history of liquidity on the Lightning Network.")]),e._v(" "),t("p",[e._v("The most common method is to rely on a server for route-finding, which sees users' payment history and therefore compromises privacy. This may also pose long-term regulatory concerns for apps relying on such servers.")]),e._v(" "),t("p",[e._v("Without a server, the client needs to download the full Lightning graph. This can be slow and performance-compromising. Worse, the Lightning graph alone doesn’t provide enough information to achieve reliable payment success, leading to the possibility that transactions may take a long time to complete, or not go through at all.")]),e._v(" "),t("p",[e._v("To achieve better payment success, the client must send lots of payments, which can be done via probing (fake payments). Probing trains data on the network graph from a client's perspective and builds up a history of liquidity on the network. While this offers a solution, probing must be done consistently, requiring the client to be online 24/7. This could instead be done by an LSP, which can offer the resulting data to clients. Additionally, information is not super portable across LSPs, so each LSP needs to do its own probing.")]),e._v(" "),t("h1",{attrs:{id:"privacy-preserving-block-fetching"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#privacy-preserving-block-fetching"}},[e._v("#")]),e._v(" Privacy-preserving Block Fetching")]),e._v(" "),t("p",[e._v("For users to see their transaction history and balance, bitcoin and Lightning wallets need to connect to and download the blockchain. Each block contains a lot of data, making downloading the full blockchain on mobile devices impractical due to bandwidth constraints.")]),e._v(" "),t("p",[e._v("The most common way to obtain blockchain data is to connect to a server using Electrum or Esplora. To do this and get the relevant information, the client has to provide their user’s list of addresses, exposing transaction histories and balances.")]),e._v(" "),t("p",[e._v("It’s difficult to fetch blockchain data without giving up privacy. One way around this is to use compact block filters, which download data from a full node and only download a select amount of blocks. While compact block filters offer better privacy than a server and are more efficient than downloading the entire blockchain, the method isn’t perfect. Compact block filters are slow to sync and still require substantial bandwidth on the user’s device, making it a less enticing tradeoff for many wallets.")]),e._v(" "),t("p",[e._v("A third option, called private information retrieval, is more future-looking. This method is efficient for clients but expensive on the server side.")]),e._v(" "),t("h1",{attrs:{id:"conclusion"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#conclusion"}},[e._v("#")]),e._v(" Conclusion")]),e._v(" "),t("p",[e._v("There are many obstacles to making non-custodial Lightning work privately on mobile devices, but it is doable. It requires a mobile-focused LN implementation, SDK, and infrastructure operated by an LSP or the application vendor. None of that needs to compromise user privacy or self-sovereignty, even though, in many designs, it does.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{398:function(e,t,n){"use strict";n.r(t);var i=n(7),o=Object(i.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Lightning development is tough. While going custodial simplifies the process, it means sacrificing user privacy, censorship resistance, and self-sovereignty, all of which contradict bitcoin’s ethos. Therefore, many companies and projects have started with or redirected their focus from building custodial to non-custodial Lightning applications.")]),e._v(" "),t("h2",{attrs:{id:"obstacles"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#obstacles"}},[e._v("#")]),e._v(" Obstacles")]),e._v(" "),t("p",[e._v("There are several basic requirements for wallets wanting to add Lightning capabilities, such as connecting to the Lightning Network via a Lightning Implementation, syncing with on-chain transactions, and opening and closing channels. When building a mobile application, developers face additional technical challenges:")]),e._v(" "),t("h2",{attrs:{id:"liquidity"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#liquidity"}},[e._v("#")]),e._v(" Liquidity")]),e._v(" "),t("p",[e._v("To receive funds via Lightning, someone must have on-chain bitcoin locked up in a channel. Transaction completion is delayed if the receiver has an empty or insufficient channel balance. For example, let’s say that someone has 50,000 sats of inbound liquidity and is trying to receive 100,000 sats. Before the Lightning transaction can be initiated, additional liquidity is required to cover the 100,000 sats total plus fees from channel reserves and anchor outputs, which are mechanisms to improve security. This is done via on-chain transactions, which come with fees.")]),e._v(" "),t("p",[e._v("Additionally, on-chain transactions must be mined into multiple blocks before being confirmed. It’s not a great user experience if someone has to do work upfront and wait roughly 30–60 minutes before they can send or receive money.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://lightningdevkit.org/blog/zero-confirmation-channels/",target:"_blank",rel:"noopener noreferrer"}},[e._v("0-conf"),t("OutboundLink")],1),e._v(" channels offer a partial solution, allowing users to receive Lightning instantly. 0-conf enables the client to trust their channel counterparty (usually an application vendor or partner) for a limited time until an on-chain transaction is confirmed. While this helps with speed, the fact that 0conf channels require some level of trust is a trade-off.")]),e._v(" "),t("p",[e._v("Liquidity Service Providers (LSPs) provide liquidity upfront through automated channel and liquidity management. LSPs supply more liquidity than required for immediate payments rather than the exact amount to ensure that remaining funds are in the channel for future transactions. If a user conducts multiple payments, it’s best to avoid doing on-chain transactions for every Lightning transaction.")]),e._v(" "),t("p",[e._v("LSPs do not want to pay excessive on-chain fees, but it’s hard to predict how often people will send and receive transactions and for how much. Therefore, there’s no straightforward way to know how much liquidity should be locked into a given channel. LSPs have to determine how much money they can contribute and how much it'll cost. This can be anywhere from aggressive (locking up a generous amount) to conservative (locking up a small amount). Ultimately, this decision results in a “compression ratio,\" i.e., the number of on-chain transactions required per Lightning transaction. Some very conservative LSPs may get a compression ratio close to one, saving their users relatively little on fees, but there is nearly always some gain to be had in using Lightning over on-chain.")]),e._v(" "),t("p",[e._v("While predicting what the compression ratio should be remains a major challenge, most solutions today offer some compression information, allowing us to learn and improve. For this reason, it’s worth deploying Lightning for instant transactions at lower costs compared to on-chain, even if it's not as common as it could be. We expect this to get better over time.")]),e._v(" "),t("h1",{attrs:{id:"receive-wakeup"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#receive-wakeup"}},[e._v("#")]),e._v(" Receive Wakeup")]),e._v(" "),t("p",[e._v("Lightning requires nodes (or, specifically, their cryptographic keys) to be online to exchange signatures and complete payments, meaning the user must be on their phone and with service. Receiving wakeups is problematic because incomplete payments are not great for the Lightning Network—it’s detrimental to keep the money for a payment locked up until someone comes back online.")]),e._v(" "),t("p",[e._v("iOS and Android operating systems help address this problem by allowing a small amount of code to run when notifications are received, even if the relevant application isn’t open. However, suppose an application is infrequently used or the device has a low battery. In that case, the application will often not get any CPU time, resulting in the payment being stuck until the user opens the app.")]),e._v(" "),t("p",[e._v("A lot of work must be done to make it possible for senders and recipients to exchange payments asynchronously, "),t("a",{attrs:{href:"https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307",target:"_blank",rel:"noopener noreferrer"}},[e._v("but a protocol sketch is in the works"),t("OutboundLink")],1),e._v(". You can find a more detailed explainer "),t("a",{attrs:{href:"https://gist.github.com/remyers/e0d2bedb7bc87371d1bdbbb6fff2edd1",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h1",{attrs:{id:"live-backups"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#live-backups"}},[e._v("#")]),e._v(" Live Backups")]),e._v(" "),t("p",[e._v("These are especially problematic when a user has to reinstall an application or loses their phone. In addition to needing their seed phrase, they’ll need the latest Lightning state data stored on their device to get their money back reliably.")]),e._v(" "),t("p",[e._v("The Lightning state changes every time a user sends or receives money, so backups must be frequently updated on a server. While some devices use Google Drive or iCloud, those protocols sync asynchronously, often leading to data being out of sync. Cloud methods sanitize data stored on the client well, but they may not ensure reliable full funds recovery if a device is lost.")]),e._v(" "),t("p",[e._v("Advanced versions of live online sync allow users to open the same wallet on multiple devices. Users often do this despite it being challenging to do with Lightning applications since two devices running simultaneously can result in losing funds.")]),e._v(" "),t("h1",{attrs:{id:"privacy-preserving-payment-routing"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#privacy-preserving-payment-routing"}},[e._v("#")]),e._v(" Privacy-preserving Payment Routing")]),e._v(" "),t("p",[e._v("Another commonly discussed issue is payment routing through the Lightning Network. This isn't easy because the route finder has to have some history of liquidity on the Lightning Network.")]),e._v(" "),t("p",[e._v("The most common method is to rely on a server for route-finding, which sees users' payment history and therefore compromises privacy. This may also pose long-term regulatory concerns for apps relying on such servers.")]),e._v(" "),t("p",[e._v("Without a server, the client needs to download the full Lightning graph. This can be slow and performance-compromising. Worse, the Lightning graph alone doesn’t provide enough information to achieve reliable payment success, leading to the possibility that transactions may take a long time to complete, or not go through at all.")]),e._v(" "),t("p",[e._v("To achieve better payment success, the client must send lots of payments, which can be done via probing (fake payments). Probing trains data on the network graph from a client's perspective and builds up a history of liquidity on the network. While this offers a solution, probing must be done consistently, requiring the client to be online 24/7. This could instead be done by an LSP, which can offer the resulting data to clients. Additionally, information is not super portable across LSPs, so each LSP needs to do its own probing.")]),e._v(" "),t("h1",{attrs:{id:"privacy-preserving-block-fetching"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#privacy-preserving-block-fetching"}},[e._v("#")]),e._v(" Privacy-preserving Block Fetching")]),e._v(" "),t("p",[e._v("For users to see their transaction history and balance, bitcoin and Lightning wallets need to connect to and download the blockchain. Each block contains a lot of data, making downloading the full blockchain on mobile devices impractical due to bandwidth constraints.")]),e._v(" "),t("p",[e._v("The most common way to obtain blockchain data is to connect to a server using Electrum or Esplora. To do this and get the relevant information, the client has to provide their user’s list of addresses, exposing transaction histories and balances.")]),e._v(" "),t("p",[e._v("It’s difficult to fetch blockchain data without giving up privacy. One way around this is to use compact block filters, which download data from a full node and only download a select amount of blocks. While compact block filters offer better privacy than a server and are more efficient than downloading the entire blockchain, the method isn’t perfect. Compact block filters are slow to sync and still require substantial bandwidth on the user’s device, making it a less enticing tradeoff for many wallets.")]),e._v(" "),t("p",[e._v("A third option, called private information retrieval, is more future-looking. This method is efficient for clients but expensive on the server side.")]),e._v(" "),t("h1",{attrs:{id:"conclusion"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#conclusion"}},[e._v("#")]),e._v(" Conclusion")]),e._v(" "),t("p",[e._v("There are many obstacles to making non-custodial Lightning work privately on mobile devices, but it is doable. It requires a mobile-focused LN implementation, SDK, and infrastructure operated by an LSP or the application vendor. None of that needs to compromise user privacy or self-sovereignty, even though, in many designs, it does.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/36.158f0474.js b/assets/js/36.88e56dc2.js similarity index 99% rename from assets/js/36.158f0474.js rename to assets/js/36.88e56dc2.js index 419ee36d2..fc309738c 100644 --- a/assets/js/36.158f0474.js +++ b/assets/js/36.88e56dc2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{402:function(t,e,n){"use strict";n.r(e);var s=n(7),a=Object(s.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("p",[t._v("The "),e("a",{attrs:{href:"https://github.com/lightningdevkit/lightning-liquidity",target:"_blank",rel:"noopener noreferrer"}},[t._v("lightning-liquidity"),e("OutboundLink")],1),t._v(" crate is an easy-to-integrate rust library that wallet developers and LSP operators can use to implement the LSP specification. The initial alpha release supports the core functionality of JIT channels under the "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/tree/main/LSPS2",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSPS2 specification"),e("OutboundLink")],1),t._v(", with plans to expand support to other key areas such as the "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/tree/main/LSPS1",target:"_blank",rel:"noopener noreferrer"}},[t._v("Channel Request protocol (LSPS1)"),e("OutboundLink")],1),t._v(", "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/edf3d925ed67405963421e7228897a343ecd53ee/LSPS5/README.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Webhook Notifications (LSPS5)"),e("OutboundLink")],1),t._v(", and the next iteration of "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/db0e99e8b65641a18c2d9b9fdf22c2dbae2af32d/LSPS4/README.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("JIT Channels (LSPS4 - Continuous JIT Channels)"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[t._v("The lightning-liquidity release marks a significant milestone in ongoing efforts to make the Lightning Network more accessible and user-friendly.")]),t._v(" "),e("h2",{attrs:{id:"how-it-all-started-lightnings-liquidity-problem"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#how-it-all-started-lightnings-liquidity-problem"}},[t._v("#")]),t._v(" How It All Started: Lightning's Liquidity Problem")]),t._v(" "),e("p",[t._v("The Lightning Network offers some relief from bitcoin’s inherent transaction speed and cost limitations. Lightning relies on a network of payment channels facilitating nearly instant, low-fee transactions. However, the promise of this technology comes with its own "),e("a",{attrs:{href:"https://lightningdevkit.org/blog/the-challenges-of-developing-non-custodial-lightning-on-mobile",target:"_blank",rel:"noopener noreferrer"}},[t._v("set of challenges"),e("OutboundLink")],1),t._v(", particularly around obtaining inbound liquidity.")]),t._v(" "),e("p",[t._v("To receive a payment, a user must have a payment channel with sufficient funds on the counterparty's side. This upfront liquidity requirement demands coordination with a counterparty willing to sell said liquidity, which has historically posed a significant barrier to entry for new users.")]),t._v(" "),e("h2",{attrs:{id:"current-approaches-and-their-shortcomings"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#current-approaches-and-their-shortcomings"}},[t._v("#")]),t._v(" Current Approaches and Their Shortcomings")]),t._v(" "),e("p",[t._v("Wallet developers often implement their own Lightning Service Provider (LSP) to distribute inbound liquidity to their users. LSPs work by agreeing to lock up their funds in channels for a fee. While this model enables more users to more easily participate in the network, it also has several problems:")]),t._v(" "),e("ul",[e("li",[e("p",[e("strong",[t._v("Lack of Interoperability")]),t._v(": Each wallet developer has to build their own LSP protocols and infrastructure, leading to a fragmented ecosystem where users are tied to specific wallets or services.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Reliability")]),t._v(": A single LSP means a single point of failure. An LSP with poorly managed liquidity could render users unable to send and receive payments.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Privacy")]),t._v(": Centralizing payments raises the potential for surveillance and data collection.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Censorship")]),t._v(": LSPs can block or be forced to block payments at their discretion.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Cost")]),t._v(": With limited competition, users could face high, non-market fees for obtaining liquidity.")])])]),t._v(" "),e("h2",{attrs:{id:"a-unified-solution-the-standardization-effort"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#a-unified-solution-the-standardization-effort"}},[t._v("#")]),t._v(" A Unified Solution: The Standardization Effort")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("A consortium of Lightning developers"),e("OutboundLink")],1),t._v(" recognized these challenges and came together with a mission to standardize a protocol for acquiring inbound liquidity. This effort aimed to create a blueprint that any wallet or LSP could adopt, fostering interoperability and competition.")]),t._v(" "),e("p",[t._v("The benefits of this standardization are:")]),t._v(" "),e("ul",[e("li",[e("p",[e("strong",[t._v("Efficiency")]),t._v(": A single, well-defined protocol simplifies the development process, enabling wallet and LSP creators to focus on innovation rather than reinventing the wheel.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Choice and Flexibility")]),t._v(": Users gain the freedom to switch between LSPs seamlessly, promoting a competitive market that drives up service quality and drives down costs.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Addressing Core Issues")]),t._v(": Diversifying the ecosystem tackles the fundamental concerns of reliability, privacy, censorship, and monopolistic practices.")])])]),t._v(" "),e("h2",{attrs:{id:"just-in-time-channels-a-cornerstone-of-the-new-protocol"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#just-in-time-channels-a-cornerstone-of-the-new-protocol"}},[t._v("#")]),t._v(" Just-In-Time Channels: A Cornerstone of the New Protocol")]),t._v(" "),e("p",[t._v("Just-In-Time (JIT) channels are the heart of the standardized protocol. These channels lower the barrier to entry for new users by allowing anyone to receive bitcoin payments over the Lightning Network without bitcoin or liquidity management.")]),t._v(" "),e("p",[t._v("Here's how it works: a user requests a Lightning invoice for an incoming payment. Upon payment, the LSP intercepts this payment, opens a 0-conf channel to the user, deducts their fee and forwards the rest of the payment to the user. This process happens almost instantaneously, removing the need for users to understand or manage liquidity themselves.")]),t._v(" "),e("h2",{attrs:{id:"introducing-lightning-liquidity"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introducing-lightning-liquidity"}},[t._v("#")]),t._v(" Introducing "),e("code",[t._v("lightning-liquidity")])]),t._v(" "),e("p",[e("code",[t._v("lightning-liquidity")]),t._v(" provides a comprehensive toolkit for implementing the JIT channel protocol and other aspects of the LSP specification. This open standard streamlines the development process and ensures that a broader audience can access the benefits of the Lightning Network.")]),t._v(" "),e("h2",{attrs:{id:"how-it-works-for-developers-and-businesses"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#how-it-works-for-developers-and-businesses"}},[t._v("#")]),t._v(" How It Works: For Developers and Businesses")]),t._v(" "),e("p",[t._v('For wallet developers, integrating "lightning-liquidity" offers users immediate access to the Lightning Network\'s capabilities without the traditional hurdles of securing inbound liquidity. Developers can embed the library into their applications, making receiving payments seamless and efficient.')]),t._v(" "),e("p",[t._v("The “lightning-liquidity” crate is already integrated directly into the "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("ldk-node"),e("OutboundLink")],1),t._v(" project allowing for an extremely easy way to get started. Here’s a short example of how to get inbound liquidity using the new liquidity functionality of ldk-node:")]),t._v(" "),e("div",{staticClass:"language-rust extra-class"},[e("pre",{pre:!0,attrs:{class:"language-rust"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning_invoice"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("msgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("secp256k1"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FromStr")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_node_id "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LSP_NODE_ID"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_node_addr "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LSP_IP_ADDR:LSP_PORT"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_token "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("“"),e("span",{pre:!0,attrs:{class:"token constant"}},[t._v("LSP_TOKEN")]),t._v("”"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// tell ldk-node we want to source liquidity using LSPS2")]),t._v("\n\tbuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_liquidity_source_lsps2")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lsp_node_addr"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lsp_node_id"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lsp_token"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" builder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// how much I want to receive")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice_amount_msat "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500_000_000")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// the maximum I’m willing to pay in fees for the channel from the LSP")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" max_total_fee_limit_msat "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5_000_000")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// the invoice I receive will be valid for this many seconds")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice_expiry_seconds "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3600")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get an invoice I can have paid without needing to set up any channels")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("receive_payment_via_jit_channel")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice_amount_msat"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" “invoice description”"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" invoice_expiry_seconds"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("max_total_fee_limit_msat"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])]),e("p",[t._v("If you are not using ldk-node then here is some example code that will help you get started implementing “lightning-liquidity” into your LDK based wallet: https://gist.github.com/johncantrell97/1d869aedcb8aef3f69874c15a0793dae")]),t._v(" "),e("p",[t._v('Businesses looking to operate as LSPs can easily leverage "lightning-liquidity" to offer liquidity services. The library simplifies the technical complexities involved in channel management, allowing businesses to focus on providing value to their customers rather than dealing with the intricacies of the Lightning Network protocol.')]),t._v(" "),e("p",[t._v("The LSPS2 protocol enables LSPs to earn a fee from every channel sold to wallet users. This fee consists of a minimum fee and a proportional fee. The proportional fee allows LSPs to earn a fee proportional to the payment size they need to route over the new channel. In contrast, the minimum fee ensures the fees they earn are guaranteed to be enough to cover their costs regardless of the payment size.")]),t._v(" "),e("p",[t._v("The protocol also allows LSPs to require and offer unique tokens that users or wallet developers can supply when requesting liquidity. The LSP can then dynamically adjust fees and channel parameters based on these tokens, allowing them to broker unique deals that cater to a wide range of potential requirements.")]),t._v(" "),e("p",[t._v("LDK LSP Server Example: https://gist.github.com/johncantrell97/dc682d2d75a0331fa83cb10a54f62b74")]),t._v(" "),e("h2",{attrs:{id:"join-us-in-shaping-the-future"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#join-us-in-shaping-the-future"}},[t._v("#")]),t._v(" Join Us in Shaping the Future")]),t._v(" "),e("p",[t._v('The launch of "lightning-liquidity" is just the beginning. We are committed to continuous improvement and expansion of the library to meet the evolving needs of the Lightning Network community. We encourage feedback, contributions, and collaboration from developers, businesses, and users. Together, we can unlock the full potential of the Lightning Network, making instant, low-cost Bitcoin transactions a reality for users worldwide.')]),t._v(" "),e("p",[t._v("For more information on the "),e("code",[t._v("lightning-liquidity")]),t._v(" library, the LSP specification, and how you can contribute to this transformative project, visit "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("the specification repository"),e("OutboundLink")],1),t._v(" and "),e("a",{attrs:{href:"https://github.com/lightningdevkit/lightning-liquidity",target:"_blank",rel:"noopener noreferrer"}},[t._v("lightning-liquidity GitHub repository"),e("OutboundLink")],1),t._v(". Together, we can build a more robust, efficient, and open Lightning Network.")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{399:function(t,e,n){"use strict";n.r(e);var s=n(7),a=Object(s.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("p",[t._v("The "),e("a",{attrs:{href:"https://github.com/lightningdevkit/lightning-liquidity",target:"_blank",rel:"noopener noreferrer"}},[t._v("lightning-liquidity"),e("OutboundLink")],1),t._v(" crate is an easy-to-integrate rust library that wallet developers and LSP operators can use to implement the LSP specification. The initial alpha release supports the core functionality of JIT channels under the "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/tree/main/LSPS2",target:"_blank",rel:"noopener noreferrer"}},[t._v("LSPS2 specification"),e("OutboundLink")],1),t._v(", with plans to expand support to other key areas such as the "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/tree/main/LSPS1",target:"_blank",rel:"noopener noreferrer"}},[t._v("Channel Request protocol (LSPS1)"),e("OutboundLink")],1),t._v(", "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/edf3d925ed67405963421e7228897a343ecd53ee/LSPS5/README.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Webhook Notifications (LSPS5)"),e("OutboundLink")],1),t._v(", and the next iteration of "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/db0e99e8b65641a18c2d9b9fdf22c2dbae2af32d/LSPS4/README.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("JIT Channels (LSPS4 - Continuous JIT Channels)"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[t._v("The lightning-liquidity release marks a significant milestone in ongoing efforts to make the Lightning Network more accessible and user-friendly.")]),t._v(" "),e("h2",{attrs:{id:"how-it-all-started-lightnings-liquidity-problem"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#how-it-all-started-lightnings-liquidity-problem"}},[t._v("#")]),t._v(" How It All Started: Lightning's Liquidity Problem")]),t._v(" "),e("p",[t._v("The Lightning Network offers some relief from bitcoin’s inherent transaction speed and cost limitations. Lightning relies on a network of payment channels facilitating nearly instant, low-fee transactions. However, the promise of this technology comes with its own "),e("a",{attrs:{href:"https://lightningdevkit.org/blog/the-challenges-of-developing-non-custodial-lightning-on-mobile",target:"_blank",rel:"noopener noreferrer"}},[t._v("set of challenges"),e("OutboundLink")],1),t._v(", particularly around obtaining inbound liquidity.")]),t._v(" "),e("p",[t._v("To receive a payment, a user must have a payment channel with sufficient funds on the counterparty's side. This upfront liquidity requirement demands coordination with a counterparty willing to sell said liquidity, which has historically posed a significant barrier to entry for new users.")]),t._v(" "),e("h2",{attrs:{id:"current-approaches-and-their-shortcomings"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#current-approaches-and-their-shortcomings"}},[t._v("#")]),t._v(" Current Approaches and Their Shortcomings")]),t._v(" "),e("p",[t._v("Wallet developers often implement their own Lightning Service Provider (LSP) to distribute inbound liquidity to their users. LSPs work by agreeing to lock up their funds in channels for a fee. While this model enables more users to more easily participate in the network, it also has several problems:")]),t._v(" "),e("ul",[e("li",[e("p",[e("strong",[t._v("Lack of Interoperability")]),t._v(": Each wallet developer has to build their own LSP protocols and infrastructure, leading to a fragmented ecosystem where users are tied to specific wallets or services.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Reliability")]),t._v(": A single LSP means a single point of failure. An LSP with poorly managed liquidity could render users unable to send and receive payments.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Privacy")]),t._v(": Centralizing payments raises the potential for surveillance and data collection.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Censorship")]),t._v(": LSPs can block or be forced to block payments at their discretion.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Cost")]),t._v(": With limited competition, users could face high, non-market fees for obtaining liquidity.")])])]),t._v(" "),e("h2",{attrs:{id:"a-unified-solution-the-standardization-effort"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#a-unified-solution-the-standardization-effort"}},[t._v("#")]),t._v(" A Unified Solution: The Standardization Effort")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("A consortium of Lightning developers"),e("OutboundLink")],1),t._v(" recognized these challenges and came together with a mission to standardize a protocol for acquiring inbound liquidity. This effort aimed to create a blueprint that any wallet or LSP could adopt, fostering interoperability and competition.")]),t._v(" "),e("p",[t._v("The benefits of this standardization are:")]),t._v(" "),e("ul",[e("li",[e("p",[e("strong",[t._v("Efficiency")]),t._v(": A single, well-defined protocol simplifies the development process, enabling wallet and LSP creators to focus on innovation rather than reinventing the wheel.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Choice and Flexibility")]),t._v(": Users gain the freedom to switch between LSPs seamlessly, promoting a competitive market that drives up service quality and drives down costs.")])]),t._v(" "),e("li",[e("p",[e("strong",[t._v("Addressing Core Issues")]),t._v(": Diversifying the ecosystem tackles the fundamental concerns of reliability, privacy, censorship, and monopolistic practices.")])])]),t._v(" "),e("h2",{attrs:{id:"just-in-time-channels-a-cornerstone-of-the-new-protocol"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#just-in-time-channels-a-cornerstone-of-the-new-protocol"}},[t._v("#")]),t._v(" Just-In-Time Channels: A Cornerstone of the New Protocol")]),t._v(" "),e("p",[t._v("Just-In-Time (JIT) channels are the heart of the standardized protocol. These channels lower the barrier to entry for new users by allowing anyone to receive bitcoin payments over the Lightning Network without bitcoin or liquidity management.")]),t._v(" "),e("p",[t._v("Here's how it works: a user requests a Lightning invoice for an incoming payment. Upon payment, the LSP intercepts this payment, opens a 0-conf channel to the user, deducts their fee and forwards the rest of the payment to the user. This process happens almost instantaneously, removing the need for users to understand or manage liquidity themselves.")]),t._v(" "),e("h2",{attrs:{id:"introducing-lightning-liquidity"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introducing-lightning-liquidity"}},[t._v("#")]),t._v(" Introducing "),e("code",[t._v("lightning-liquidity")])]),t._v(" "),e("p",[e("code",[t._v("lightning-liquidity")]),t._v(" provides a comprehensive toolkit for implementing the JIT channel protocol and other aspects of the LSP specification. This open standard streamlines the development process and ensures that a broader audience can access the benefits of the Lightning Network.")]),t._v(" "),e("h2",{attrs:{id:"how-it-works-for-developers-and-businesses"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#how-it-works-for-developers-and-businesses"}},[t._v("#")]),t._v(" How It Works: For Developers and Businesses")]),t._v(" "),e("p",[t._v('For wallet developers, integrating "lightning-liquidity" offers users immediate access to the Lightning Network\'s capabilities without the traditional hurdles of securing inbound liquidity. Developers can embed the library into their applications, making receiving payments seamless and efficient.')]),t._v(" "),e("p",[t._v("The “lightning-liquidity” crate is already integrated directly into the "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[t._v("ldk-node"),e("OutboundLink")],1),t._v(" project allowing for an extremely easy way to get started. Here’s a short example of how to get inbound liquidity using the new liquidity functionality of ldk-node:")]),t._v(" "),e("div",{staticClass:"language-rust extra-class"},[e("pre",{pre:!0,attrs:{class:"language-rust"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning_invoice"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("lightning"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("msgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("secp256k1"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("ldk_node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("bitcoin"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FromStr")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_node_id "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PublicKey")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LSP_NODE_ID"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_node_addr "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LSP_IP_ADDR:LSP_PORT"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lsp_token "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("“"),e("span",{pre:!0,attrs:{class:"token constant"}},[t._v("LSP_TOKEN")]),t._v("”"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Builder")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// tell ldk-node we want to source liquidity using LSPS2")]),t._v("\n\tbuilder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("set_liquidity_source_lsps2")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lsp_node_addr"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lsp_node_id"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lsp_token"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" node "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" builder"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tnode"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// how much I want to receive")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice_amount_msat "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500_000_000")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// the maximum I’m willing to pay in fees for the channel from the LSP")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" max_total_fee_limit_msat "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5_000_000")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// the invoice I receive will be valid for this many seconds")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice_expiry_seconds "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3600")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\n\t"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get an invoice I can have paid without needing to set up any channels")]),t._v("\n\t"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("receive_payment_via_jit_channel")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice_amount_msat"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" “invoice description”"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" invoice_expiry_seconds"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("max_total_fee_limit_msat"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])]),e("p",[t._v("If you are not using ldk-node then here is some example code that will help you get started implementing “lightning-liquidity” into your LDK based wallet: https://gist.github.com/johncantrell97/1d869aedcb8aef3f69874c15a0793dae")]),t._v(" "),e("p",[t._v('Businesses looking to operate as LSPs can easily leverage "lightning-liquidity" to offer liquidity services. The library simplifies the technical complexities involved in channel management, allowing businesses to focus on providing value to their customers rather than dealing with the intricacies of the Lightning Network protocol.')]),t._v(" "),e("p",[t._v("The LSPS2 protocol enables LSPs to earn a fee from every channel sold to wallet users. This fee consists of a minimum fee and a proportional fee. The proportional fee allows LSPs to earn a fee proportional to the payment size they need to route over the new channel. In contrast, the minimum fee ensures the fees they earn are guaranteed to be enough to cover their costs regardless of the payment size.")]),t._v(" "),e("p",[t._v("The protocol also allows LSPs to require and offer unique tokens that users or wallet developers can supply when requesting liquidity. The LSP can then dynamically adjust fees and channel parameters based on these tokens, allowing them to broker unique deals that cater to a wide range of potential requirements.")]),t._v(" "),e("p",[t._v("LDK LSP Server Example: https://gist.github.com/johncantrell97/dc682d2d75a0331fa83cb10a54f62b74")]),t._v(" "),e("h2",{attrs:{id:"join-us-in-shaping-the-future"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#join-us-in-shaping-the-future"}},[t._v("#")]),t._v(" Join Us in Shaping the Future")]),t._v(" "),e("p",[t._v('The launch of "lightning-liquidity" is just the beginning. We are committed to continuous improvement and expansion of the library to meet the evolving needs of the Lightning Network community. We encourage feedback, contributions, and collaboration from developers, businesses, and users. Together, we can unlock the full potential of the Lightning Network, making instant, low-cost Bitcoin transactions a reality for users worldwide.')]),t._v(" "),e("p",[t._v("For more information on the "),e("code",[t._v("lightning-liquidity")]),t._v(" library, the LSP specification, and how you can contribute to this transformative project, visit "),e("a",{attrs:{href:"https://github.com/BitcoinAndLightningLayerSpecs/lsp",target:"_blank",rel:"noopener noreferrer"}},[t._v("the specification repository"),e("OutboundLink")],1),t._v(" and "),e("a",{attrs:{href:"https://github.com/lightningdevkit/lightning-liquidity",target:"_blank",rel:"noopener noreferrer"}},[t._v("lightning-liquidity GitHub repository"),e("OutboundLink")],1),t._v(". Together, we can build a more robust, efficient, and open Lightning Network.")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/37.7be78bca.js b/assets/js/37.7fe0f295.js similarity index 98% rename from assets/js/37.7be78bca.js rename to assets/js/37.7fe0f295.js index 3c66dd6b6..eebfa8f88 100644 --- a/assets/js/37.7be78bca.js +++ b/assets/js/37.7fe0f295.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{405:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Support for 0-conf channels became available in the Lightning Development Kit’s June 2022, "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/releases/tag/v0.0.107",target:"_blank",rel:"noopener noreferrer"}},[e._v("107 release"),t("OutboundLink")],1),e._v(". A 0-conf channel allows peers to start using a channel as soon as the funding transaction is broadcast instead of waiting for multiple confirmations. By temporarily trusting the person initiating the channel open, 0-conf channels enable instant onboarding to the Lightning Network.")]),e._v(" "),t("h2",{attrs:{id:"what-is-a-confirmation"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-is-a-confirmation"}},[e._v("#")]),e._v(" What is a confirmation?")]),e._v(" "),t("p",[e._v("A confirmation refers to each block that has been mined with a particular transaction included in the chain. When a transaction is first broadcast to the network but has not yet been included in a block, it has zero confirmations. When the transaction is included in a block, it is said to have one confirmation. Each block mined on top of the first block gives a transaction additional confirmations.")]),e._v(" "),t("h2",{attrs:{id:"why-does-the-number-of-confirmations-matter"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-does-the-number-of-confirmations-matter"}},[e._v("#")]),e._v(" Why does the number of confirmations matter?")]),e._v(" "),t("p",[e._v("It’s a way to measure the security and finality of transactions. The only way a miner can reverse a transaction is by a process called reorganization. This requires the miner to build a chain of blocks with more work than the currently accepted chain. Each block mined on top of a block that contains a transaction makes it harder to reorganize. In bitcoin’s history, we’ve seen a 4-block reorganization only a couple of times, a 3-block reorganization a handful of times, a 2-block reorganization a few dozen times, and hundreds of 1-block reorganizations.")]),e._v(" "),t("p",[e._v("This is why you should wait six confirmations before considering a high-value transaction complete. A 0-conf transaction is dangerous to accept if you don’t trust the sender since there’s no guarantee that it will ever be included in a block. It’s possible that the fee is too low or another transaction double spends its inputs.")]),e._v(" "),t("h2",{attrs:{id:"what-does-this-have-to-do-with-the-lightning-network"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-does-this-have-to-do-with-the-lightning-network"}},[e._v("#")]),e._v(" What does this have to do with the Lightning Network?")]),e._v(" "),t("p",[e._v("When you open a channel on the Lightning Network, you create and broadcast a transaction that funds a multi-sig address shared between channel partners. Most implementations wait for six confirmations before letting a channel route payments. Like any transaction, it could be double-spent, have erroneously low fees, or be reorganized out by miners. If you receive money over a channel where the funding transaction is never confirmed, you will lose any money received or forwarded over that channel.")]),e._v(" "),t("p",[e._v("That brings us to 0-conf channels, which can be used once the transaction appears in both parties' mempools without being mined. This means that the same risks exist when accepting payments over a 0-conf channel as on-chain payments with zero confirmations. However, If you accept a 0-conf payment or channel then you are putting trust into the system.")]),e._v(" "),t("p",[e._v("0-conf channels are somewhat controversial because one of bitcoin’s main benefits is that it enables peer-to-peer payments without requiring you to trust your peers or any other intermediaries. With 0-conf channels, you trust that your peer won’t attempt to double-spend the transaction inputs and that miners will include and build on top of this transaction. While you can do some things to gain confidence that the transaction will confirm, such as verifying the fee rate and being well connected to the network, you can never be certain.")]),e._v(" "),t("p",[e._v("Despite the trust required when working with 0-conf transactions, it’s worth noting that in the case of 0-conf channels, the trust is only with your peer, which is not necessarily the person sending you the money. This is quite different from 0-conf on-chain payments where you have to trust every individual sender.")]),e._v(" "),t("h2",{attrs:{id:"why-or-when-might-0-conf-channels-be-useful"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-or-when-might-0-conf-channels-be-useful"}},[e._v("#")]),e._v(" Why or when might 0-conf channels be useful?")]),e._v(" "),t("p",[e._v("Well, they enable instant Lightning payments where trust is minimized as confirmations occur. This can be useful in situations where you already trust your peers to some extent, such as friends, family, or reliable business relationships.")]),e._v(" "),t("p",[e._v("0-conf channels can also enable some interesting liquidity/onboarding use-cases. If you trust your LSP or wallet provider, it’s possible to receive a payment over Lightning without having to set up a channel first. Your LSP or wallet provider can open a 0-conf channel with you on-demand as your first payment arrives.")]),e._v(" "),t("h2",{attrs:{id:"conclusion"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#conclusion"}},[e._v("#")]),e._v(" Conclusion")]),e._v(" "),t("p",[e._v("0-conf channels can be a useful tool in situations where there is some trust. Do not accept 0-conf channels by default or from people you don’t know. Check out "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=JjuN6aVv9DI",target:"_blank",rel:"noopener noreferrer"}},[e._v("this video"),t("OutboundLink")],1),e._v(" to see how support for 0-conf channels was added to Sensei, an LDK-based Lightning node.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{400:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("p",[e._v("Support for 0-conf channels became available in the Lightning Development Kit’s June 2022, "),t("a",{attrs:{href:"https://github.com/lightningdevkit/rust-lightning/releases/tag/v0.0.107",target:"_blank",rel:"noopener noreferrer"}},[e._v("107 release"),t("OutboundLink")],1),e._v(". A 0-conf channel allows peers to start using a channel as soon as the funding transaction is broadcast instead of waiting for multiple confirmations. By temporarily trusting the person initiating the channel open, 0-conf channels enable instant onboarding to the Lightning Network.")]),e._v(" "),t("h2",{attrs:{id:"what-is-a-confirmation"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-is-a-confirmation"}},[e._v("#")]),e._v(" What is a confirmation?")]),e._v(" "),t("p",[e._v("A confirmation refers to each block that has been mined with a particular transaction included in the chain. When a transaction is first broadcast to the network but has not yet been included in a block, it has zero confirmations. When the transaction is included in a block, it is said to have one confirmation. Each block mined on top of the first block gives a transaction additional confirmations.")]),e._v(" "),t("h2",{attrs:{id:"why-does-the-number-of-confirmations-matter"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-does-the-number-of-confirmations-matter"}},[e._v("#")]),e._v(" Why does the number of confirmations matter?")]),e._v(" "),t("p",[e._v("It’s a way to measure the security and finality of transactions. The only way a miner can reverse a transaction is by a process called reorganization. This requires the miner to build a chain of blocks with more work than the currently accepted chain. Each block mined on top of a block that contains a transaction makes it harder to reorganize. In bitcoin’s history, we’ve seen a 4-block reorganization only a couple of times, a 3-block reorganization a handful of times, a 2-block reorganization a few dozen times, and hundreds of 1-block reorganizations.")]),e._v(" "),t("p",[e._v("This is why you should wait six confirmations before considering a high-value transaction complete. A 0-conf transaction is dangerous to accept if you don’t trust the sender since there’s no guarantee that it will ever be included in a block. It’s possible that the fee is too low or another transaction double spends its inputs.")]),e._v(" "),t("h2",{attrs:{id:"what-does-this-have-to-do-with-the-lightning-network"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#what-does-this-have-to-do-with-the-lightning-network"}},[e._v("#")]),e._v(" What does this have to do with the Lightning Network?")]),e._v(" "),t("p",[e._v("When you open a channel on the Lightning Network, you create and broadcast a transaction that funds a multi-sig address shared between channel partners. Most implementations wait for six confirmations before letting a channel route payments. Like any transaction, it could be double-spent, have erroneously low fees, or be reorganized out by miners. If you receive money over a channel where the funding transaction is never confirmed, you will lose any money received or forwarded over that channel.")]),e._v(" "),t("p",[e._v("That brings us to 0-conf channels, which can be used once the transaction appears in both parties' mempools without being mined. This means that the same risks exist when accepting payments over a 0-conf channel as on-chain payments with zero confirmations. However, If you accept a 0-conf payment or channel then you are putting trust into the system.")]),e._v(" "),t("p",[e._v("0-conf channels are somewhat controversial because one of bitcoin’s main benefits is that it enables peer-to-peer payments without requiring you to trust your peers or any other intermediaries. With 0-conf channels, you trust that your peer won’t attempt to double-spend the transaction inputs and that miners will include and build on top of this transaction. While you can do some things to gain confidence that the transaction will confirm, such as verifying the fee rate and being well connected to the network, you can never be certain.")]),e._v(" "),t("p",[e._v("Despite the trust required when working with 0-conf transactions, it’s worth noting that in the case of 0-conf channels, the trust is only with your peer, which is not necessarily the person sending you the money. This is quite different from 0-conf on-chain payments where you have to trust every individual sender.")]),e._v(" "),t("h2",{attrs:{id:"why-or-when-might-0-conf-channels-be-useful"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#why-or-when-might-0-conf-channels-be-useful"}},[e._v("#")]),e._v(" Why or when might 0-conf channels be useful?")]),e._v(" "),t("p",[e._v("Well, they enable instant Lightning payments where trust is minimized as confirmations occur. This can be useful in situations where you already trust your peers to some extent, such as friends, family, or reliable business relationships.")]),e._v(" "),t("p",[e._v("0-conf channels can also enable some interesting liquidity/onboarding use-cases. If you trust your LSP or wallet provider, it’s possible to receive a payment over Lightning without having to set up a channel first. Your LSP or wallet provider can open a 0-conf channel with you on-demand as your first payment arrives.")]),e._v(" "),t("h2",{attrs:{id:"conclusion"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#conclusion"}},[e._v("#")]),e._v(" Conclusion")]),e._v(" "),t("p",[e._v("0-conf channels can be a useful tool in situations where there is some trust. Do not accept 0-conf channels by default or from people you don’t know. Check out "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=JjuN6aVv9DI",target:"_blank",rel:"noopener noreferrer"}},[e._v("this video"),t("OutboundLink")],1),e._v(" to see how support for 0-conf channels was added to Sensei, an LDK-based Lightning node.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/38.a3fc73ba.js b/assets/js/38.2f8343f4.js similarity index 99% rename from assets/js/38.a3fc73ba.js rename to assets/js/38.2f8343f4.js index 9038f4ffe..44515c765 100644 --- a/assets/js/38.a3fc73ba.js +++ b/assets/js/38.2f8343f4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{403:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"block-source"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#block-source"}},[t._v("#")]),t._v(" Block Source")]),t._v(" "),s("p",[t._v("Implementing the "),s("code",[t._v("BlockSource")]),t._v(" interface requires defining methods for fetching\nheaders, blocks, and the best block hash.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_header")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHeaderData")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_best_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("For instance, you may implement this interface by querying Bitcoin Core's JSON\nRPC interface, which happens to be a sample implementation provided by\n"),s("code",[t._v("lightning-block-sync")]),t._v(".")]),t._v(" "),s("p",[t._v("Let's walk through the use case where LDK receives full blocks.")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{401:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"block-source"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#block-source"}},[t._v("#")]),t._v(" Block Source")]),t._v(" "),s("p",[t._v("Implementing the "),s("code",[t._v("BlockSource")]),t._v(" interface requires defining methods for fetching\nheaders, blocks, and the best block hash.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_header")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHeaderData")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_best_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("For instance, you may implement this interface by querying Bitcoin Core's JSON\nRPC interface, which happens to be a sample implementation provided by\n"),s("code",[t._v("lightning-block-sync")]),t._v(".")]),t._v(" "),s("p",[t._v("Let's walk through the use case where LDK receives full blocks.")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/39.99913eba.js b/assets/js/39.17645029.js similarity index 97% rename from assets/js/39.99913eba.js rename to assets/js/39.17645029.js index 1f8c02f01..267f98e1c 100644 --- a/assets/js/39.99913eba.js +++ b/assets/js/39.17645029.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{404:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"chain-activity"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#chain-activity"}},[e._v("#")]),e._v(" Chain Activity")]),e._v(" "),t("p",[e._v("Initially, our node doesn't have any channels and hence has no data to monitor\nfor on-chain. When a channel is opened with a peer, the "),t("code",[e._v("ChannelManager")]),e._v(" creates\na "),t("code",[e._v("ChannelMonitor")]),e._v(" and passes it to the "),t("code",[e._v("ChainMonitor")]),e._v(" to watch.")]),e._v(" "),t("p",[e._v("At this point, you need to feed LDK any chain data of interest so that it can\nrespond accordingly. It supports receiving either full blocks or pre-filtered\nblocks using the "),t("code",[e._v("chain::Listen")]),e._v(" interface. While block data can be sourced from\nanywhere, it is your responsibility to call the "),t("code",[e._v("block_connected")]),e._v(" and\n"),t("code",[e._v("block_disconnected")]),e._v(" methods on "),t("code",[e._v("ChannelManager")]),e._v(" and "),t("code",[e._v("ChainMonitor")]),e._v(". This allows\nthem to update channel state and respond to on-chain events, respectively.")]),e._v(" "),t("p",[e._v("LDK comes with a "),t("code",[e._v("lightning-block-sync")]),e._v(" utility that handles polling a block\nsource for the best chain tip, detecting chain forks, and notifying listeners\nwhen blocks are connected and disconnected. It can be configured to:")]),e._v(" "),t("ul",[t("li",[e._v("Poll a custom "),t("code",[e._v("BlockSource")])]),e._v(" "),t("li",[e._v("Notify "),t("code",[e._v("ChannelManager")]),e._v(" and "),t("code",[e._v("ChainMonitor")]),e._v(" of block events")])]),e._v(" "),t("p",[e._v("It is your choice as to whether you use this utility or your own to feed the\nrequired chain data to LDK. If you choose to use it, you will need to implement\nthe "),t("code",[e._v("BlockSource")]),e._v(" interface or use one of the samples that it provides.")]),e._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[e._v("Note")]),e._v(" "),t("p",[e._v("Currently, "),t("code",[e._v("lightning-block-sync")]),e._v(" is only available in Rust.")])])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{403:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"chain-activity"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#chain-activity"}},[e._v("#")]),e._v(" Chain Activity")]),e._v(" "),t("p",[e._v("Initially, our node doesn't have any channels and hence has no data to monitor\nfor on-chain. When a channel is opened with a peer, the "),t("code",[e._v("ChannelManager")]),e._v(" creates\na "),t("code",[e._v("ChannelMonitor")]),e._v(" and passes it to the "),t("code",[e._v("ChainMonitor")]),e._v(" to watch.")]),e._v(" "),t("p",[e._v("At this point, you need to feed LDK any chain data of interest so that it can\nrespond accordingly. It supports receiving either full blocks or pre-filtered\nblocks using the "),t("code",[e._v("chain::Listen")]),e._v(" interface. While block data can be sourced from\nanywhere, it is your responsibility to call the "),t("code",[e._v("block_connected")]),e._v(" and\n"),t("code",[e._v("block_disconnected")]),e._v(" methods on "),t("code",[e._v("ChannelManager")]),e._v(" and "),t("code",[e._v("ChainMonitor")]),e._v(". This allows\nthem to update channel state and respond to on-chain events, respectively.")]),e._v(" "),t("p",[e._v("LDK comes with a "),t("code",[e._v("lightning-block-sync")]),e._v(" utility that handles polling a block\nsource for the best chain tip, detecting chain forks, and notifying listeners\nwhen blocks are connected and disconnected. It can be configured to:")]),e._v(" "),t("ul",[t("li",[e._v("Poll a custom "),t("code",[e._v("BlockSource")])]),e._v(" "),t("li",[e._v("Notify "),t("code",[e._v("ChannelManager")]),e._v(" and "),t("code",[e._v("ChainMonitor")]),e._v(" of block events")])]),e._v(" "),t("p",[e._v("It is your choice as to whether you use this utility or your own to feed the\nrequired chain data to LDK. If you choose to use it, you will need to implement\nthe "),t("code",[e._v("BlockSource")]),e._v(" interface or use one of the samples that it provides.")]),e._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[e._v("Note")]),e._v(" "),t("p",[e._v("Currently, "),t("code",[e._v("lightning-block-sync")]),e._v(" is only available in Rust.")])])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/40.e47a2a35.js b/assets/js/40.d7047a61.js similarity index 98% rename from assets/js/40.e47a2a35.js rename to assets/js/40.d7047a61.js index 51824696d..b12955439 100644 --- a/assets/js/40.e47a2a35.js +++ b/assets/js/40.d7047a61.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{406:function(t,e,n){"use strict";n.r(e);var i=n(7),o=Object(i.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"confirmed-transactions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#confirmed-transactions"}},[t._v("#")]),t._v(" Confirmed Transactions")]),t._v(" "),e("p",[t._v("Up until this point, we've explored how to notify LDK of chain activity using\nblocks. But what if you're sourcing chain activity from a place that doesn't\nprovide a block-centric interface, like Electrum?")]),t._v(" "),e("p",[t._v("LDK's "),e("code",[t._v("ChannelManager")]),t._v(" and "),e("code",[t._v("ChainMonitor")]),t._v(" implement a\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Confirm")]),e("OutboundLink")],1),t._v("\ninterface to support this use case, analogous to the block-oriented\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Listen.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Listen")]),e("OutboundLink")],1),t._v("\ninterface which we've been using up until now. With this alternative approach,\nyou still need to give LDK information about chain activity,\nbut only for transactions of interest. To this end, you must call\n"),e("code",[t._v("Confirm::transactions_confirmed")]),t._v(" when any transactions identified by\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Filter")]),e("OutboundLink")],1),t._v("'s\n"),e("code",[t._v("register_tx")]),t._v("/"),e("code",[t._v("register_output")]),t._v(" methods are confirmed.")]),t._v(" "),e("p",[t._v("You also need to notify LDK of any transactions with insufficient confirmations\nthat have been reorganized out of the chain. Transactions that need to be monitored for such\nreorganization are returned by "),e("code",[t._v("Confirm::get_relevant_txids")]),t._v(". If any of these transactions become\nunconfirmed, you must call "),e("code",[t._v("Confirm::transaction_unconfirmed")]),t._v(".")]),t._v(" "),e("p",[t._v("Lastly, you must notify LDK whenever a new chain tip is available using\nthe "),e("code",[t._v("Confirm::best_block_updated")]),t._v(" method. See the documentation for a full\npicture of how this interface is intended to be used.")]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Note that the described methods of "),e("code",[t._v("Confirm")]),t._v(" must be called in accordance with the ordering requirements\ndescribed in the "),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html#order",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("Confirm")]),t._v(" documentation"),e("OutboundLink")],1)])]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Note that the described methods of "),e("code",[t._v("Confirm")]),t._v(" must be called both on the\n"),e("code",[t._v("ChannelManager")]),t._v(" "),e("em",[t._v("and")]),t._v(" the "),e("code",[t._v("ChainMonitor")]),t._v(".")])]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Be advised that "),e("code",[t._v("chain::Confirm")]),t._v(" is a less mature interface than\n"),e("code",[t._v("chain::Listen")]),t._v(". As such, there is not yet a utility like\n"),e("code",[t._v("lightning-block-sync")]),t._v(" to use for interacting with clients like Electrum.")])])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{404:function(t,e,n){"use strict";n.r(e);var i=n(7),o=Object(i.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"confirmed-transactions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#confirmed-transactions"}},[t._v("#")]),t._v(" Confirmed Transactions")]),t._v(" "),e("p",[t._v("Up until this point, we've explored how to notify LDK of chain activity using\nblocks. But what if you're sourcing chain activity from a place that doesn't\nprovide a block-centric interface, like Electrum?")]),t._v(" "),e("p",[t._v("LDK's "),e("code",[t._v("ChannelManager")]),t._v(" and "),e("code",[t._v("ChainMonitor")]),t._v(" implement a\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Confirm")]),e("OutboundLink")],1),t._v("\ninterface to support this use case, analogous to the block-oriented\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Listen.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Listen")]),e("OutboundLink")],1),t._v("\ninterface which we've been using up until now. With this alternative approach,\nyou still need to give LDK information about chain activity,\nbut only for transactions of interest. To this end, you must call\n"),e("code",[t._v("Confirm::transactions_confirmed")]),t._v(" when any transactions identified by\n"),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("chain::Filter")]),e("OutboundLink")],1),t._v("'s\n"),e("code",[t._v("register_tx")]),t._v("/"),e("code",[t._v("register_output")]),t._v(" methods are confirmed.")]),t._v(" "),e("p",[t._v("You also need to notify LDK of any transactions with insufficient confirmations\nthat have been reorganized out of the chain. Transactions that need to be monitored for such\nreorganization are returned by "),e("code",[t._v("Confirm::get_relevant_txids")]),t._v(". If any of these transactions become\nunconfirmed, you must call "),e("code",[t._v("Confirm::transaction_unconfirmed")]),t._v(".")]),t._v(" "),e("p",[t._v("Lastly, you must notify LDK whenever a new chain tip is available using\nthe "),e("code",[t._v("Confirm::best_block_updated")]),t._v(" method. See the documentation for a full\npicture of how this interface is intended to be used.")]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Note that the described methods of "),e("code",[t._v("Confirm")]),t._v(" must be called in accordance with the ordering requirements\ndescribed in the "),e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html#order",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("Confirm")]),t._v(" documentation"),e("OutboundLink")],1)])]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Note that the described methods of "),e("code",[t._v("Confirm")]),t._v(" must be called both on the\n"),e("code",[t._v("ChannelManager")]),t._v(" "),e("em",[t._v("and")]),t._v(" the "),e("code",[t._v("ChainMonitor")]),t._v(".")])]),t._v(" "),e("div",{staticClass:"custom-block tip"},[e("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),e("p",[t._v("Be advised that "),e("code",[t._v("chain::Confirm")]),t._v(" is a less mature interface than\n"),e("code",[t._v("chain::Listen")]),t._v(". As such, there is not yet a utility like\n"),e("code",[t._v("lightning-block-sync")]),t._v(" to use for interacting with clients like Electrum.")])])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/41.86439522.js b/assets/js/41.2a3fb2db.js similarity index 94% rename from assets/js/41.86439522.js rename to assets/js/41.2a3fb2db.js index 26df3679b..01e3ec517 100644 --- a/assets/js/41.86439522.js +++ b/assets/js/41.2a3fb2db.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{407:function(n,e,t){"use strict";t.r(e);var a=t(7),o=Object(a.a)({},(function(){var n=this,e=n._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":n.$parent.slotKey}},[e("h1",{attrs:{id:"full-blocks"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#full-blocks"}},[n._v("#")]),n._v(" Full Blocks")]),n._v(" "),e("p",[n._v("If your Lightning node is backed by a Bitcoin full node, the operation is\nstraight forward: call the appropriate methods on "),e("code",[n._v("ChannelManager")]),n._v(" and\n"),e("code",[n._v("ChainMonitor")]),n._v(" as blocks are connected and disconnected. LDK will handle the\nrest!")]),n._v(" "),e("p",[n._v("So what happens? The "),e("code",[n._v("ChannelManager")]),n._v(" examines the block's transactions and\nupdates the internal channel state as needed. The "),e("code",[n._v("ChainMonitor")]),n._v(" will detect\nany spends of the channel funding transaction or any pertinent transaction\noutputs, tracking them as necessary.")]),n._v(" "),e("p",[n._v("If necessary, LDK will broadcast a transaction on your behalf. More on that\nlater. For now, let's look at the more interesting case of pre-filtered blocks.")])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{405:function(n,e,t){"use strict";t.r(e);var a=t(7),o=Object(a.a)({},(function(){var n=this,e=n._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":n.$parent.slotKey}},[e("h1",{attrs:{id:"full-blocks"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#full-blocks"}},[n._v("#")]),n._v(" Full Blocks")]),n._v(" "),e("p",[n._v("If your Lightning node is backed by a Bitcoin full node, the operation is\nstraight forward: call the appropriate methods on "),e("code",[n._v("ChannelManager")]),n._v(" and\n"),e("code",[n._v("ChainMonitor")]),n._v(" as blocks are connected and disconnected. LDK will handle the\nrest!")]),n._v(" "),e("p",[n._v("So what happens? The "),e("code",[n._v("ChannelManager")]),n._v(" examines the block's transactions and\nupdates the internal channel state as needed. The "),e("code",[n._v("ChainMonitor")]),n._v(" will detect\nany spends of the channel funding transaction or any pertinent transaction\noutputs, tracking them as necessary.")]),n._v(" "),e("p",[n._v("If necessary, LDK will broadcast a transaction on your behalf. More on that\nlater. For now, let's look at the more interesting case of pre-filtered blocks.")])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/42.c74f00dd.js b/assets/js/42.2ea2bf57.js similarity index 99% rename from assets/js/42.c74f00dd.js rename to assets/js/42.2ea2bf57.js index b8c4ab8f0..438841ce3 100644 --- a/assets/js/42.c74f00dd.js +++ b/assets/js/42.2ea2bf57.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{409:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"pre-filtered-blocks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#pre-filtered-blocks"}},[t._v("#")]),t._v(" Pre-filtered Blocks")]),t._v(" "),s("p",[t._v("For environments that are resource constrained, receiving and processing all\ntransaction data may not be feasible. LDK handles this case by signaling back\nwhich transactions and outputs it is interested in. This information can then be\nused to filter blocks prior to sending them to your node.")]),t._v(" "),s("p",[t._v("For example, if your block source is an Electrum client, you can pass along this\ninformation to it. Or, if you are making use of a BIP 157 client, you can check\nif a block contains relevant transactions before fetching it.")]),t._v(" "),s("p",[t._v("So how does this work in practice? "),s("code",[t._v("ChainMonitor")]),t._v(" is parameterized by an\noptional type that implements "),s("code",[t._v("chain::Filter")]),t._v(":")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",java:"Java"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Txid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"java",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" tx_filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FilterInterface")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("When this is provided, "),s("code",[t._v("ChainMonitor")]),t._v(" will call back to the filter as channels\nare opened and blocks connected. This gives the opportunity for the source to\npre-filter blocks as desired.")]),t._v(" "),s("p",[t._v("Regardless, when a block is connected, its header must be processed by LDK.")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{407:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"pre-filtered-blocks"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#pre-filtered-blocks"}},[t._v("#")]),t._v(" Pre-filtered Blocks")]),t._v(" "),s("p",[t._v("For environments that are resource constrained, receiving and processing all\ntransaction data may not be feasible. LDK handles this case by signaling back\nwhich transactions and outputs it is interested in. This information can then be\nused to filter blocks prior to sending them to your node.")]),t._v(" "),s("p",[t._v("For example, if your block source is an Electrum client, you can pass along this\ninformation to it. Or, if you are making use of a BIP 157 client, you can check\nif a block contains relevant transactions before fetching it.")]),t._v(" "),s("p",[t._v("So how does this work in practice? "),s("code",[t._v("ChainMonitor")]),t._v(" is parameterized by an\noptional type that implements "),s("code",[t._v("chain::Filter")]),t._v(":")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",java:"Java"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Txid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"java",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" tx_filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FilterInterface")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("byte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("When this is provided, "),s("code",[t._v("ChainMonitor")]),t._v(" will call back to the filter as channels\nare opened and blocks connected. This gives the opportunity for the source to\npre-filter blocks as desired.")]),t._v(" "),s("p",[t._v("Regardless, when a block is connected, its header must be processed by LDK.")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/43.9dd761af.js b/assets/js/43.563db6ac.js similarity index 93% rename from assets/js/43.9dd761af.js rename to assets/js/43.563db6ac.js index f750c9a65..1c6b8feae 100644 --- a/assets/js/43.9dd761af.js +++ b/assets/js/43.563db6ac.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{410:function(t,n,o){"use strict";o.r(n);var a=o(7),e=Object(a.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"transaction-broadcasting"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#transaction-broadcasting"}},[t._v("#")]),t._v(" Transaction Broadcasting")]),t._v(" "),n("p",[t._v("Inevitably, LDK will need to broadcast transactions on your behalf. As you\nnotify it of blocks, it will determine if it should broadcast a transaction and\ndo so using an implementation of "),n("code",[t._v("BroadcasterInterface")]),t._v(" that you have provided.")]),t._v(" "),n("p",[t._v("And as those transactions or those from your peers are confirmed on-chain, they\nwill be likewise processed when notified of a connected block. Thus, continuing\nthe cycle.")])])}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{408:function(t,n,o){"use strict";o.r(n);var a=o(7),e=Object(a.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"transaction-broadcasting"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#transaction-broadcasting"}},[t._v("#")]),t._v(" Transaction Broadcasting")]),t._v(" "),n("p",[t._v("Inevitably, LDK will need to broadcast transactions on your behalf. As you\nnotify it of blocks, it will determine if it should broadcast a transaction and\ndo so using an implementation of "),n("code",[t._v("BroadcasterInterface")]),t._v(" that you have provided.")]),t._v(" "),n("p",[t._v("And as those transactions or those from your peers are confirmed on-chain, they\nwill be likewise processed when notified of a connected block. Thus, continuing\nthe cycle.")])])}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/44.a8016ab9.js b/assets/js/44.b3a75116.js similarity index 99% rename from assets/js/44.a8016ab9.js rename to assets/js/44.b3a75116.js index 241588a6d..ce64fa244 100644 --- a/assets/js/44.a8016ab9.js +++ b/assets/js/44.b3a75116.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{412:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"closing-a-channel"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#closing-a-channel"}},[t._v("#")]),t._v(" Closing a Channel")]),t._v(" "),s("p",[t._v("Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs will be accepted on the given channel, and after additional timeout/the closing of all pending HTLCs, the channel will be closed on chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_channels")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("channel"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" channel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Channel not found"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example: Cooperative close")]),t._v("\nchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to close channel"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example: Unilateral close")]),t._v("\nchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("force_close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to close channel"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Result_NoneAPIErrorZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_NoneAPIErrorZ_Err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle error")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful close")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Add Channel Id in bytes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Add Counterparty Node Id in bytes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("closeChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Channel Closed")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("To claim Funds directly into a custom wallet like BDK wallet using a custom "),s("code",[t._v("KeysManager")]),t._v(" see the "),s("RouterLink",{attrs:{to:"/key_management/"}},[t._v("Key Management")]),t._v(" guide for more info.")],1),t._v(" "),s("h1",{attrs:{id:"spendableoutputs-event-handling"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spendableoutputs-event-handling"}},[t._v("#")]),t._v(" SpendableOutputs Event Handling")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputs")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// of! While a `StaticOutput` descriptor is just an output to a static, well-known key,")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// other descriptors are not currently ever regenerated for you by LDK. Once we return")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// from this method, the descriptor will be gone, and you may lose track of some funds.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Here we simply persist them to disk, with a background task running which will try")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// to spend them regularly (possibly duplicatively/RBF'ing them). These can just be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// treated as normal funds where possible - they are only spendable by us and there is")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// no rush to claim them.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" output "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("hex_utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hex_str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_secure_random_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note that if the type here changes our read code needs to change as well.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fs_store"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("PENDING_SPENDABLE_OUTPUT_DIR")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("encode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example where we spend straight to our BDK based wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SpendableOutputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("outputs\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" OnchainWallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getNewAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" script "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("TxOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("arrayOf")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txOut"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u32Z"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("None"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("none")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_TransactionNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_TransactionNoneZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("arrayOf")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("plus")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n LDKBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Exception"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Error: ')]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("${")]),s("span",{pre:!0,attrs:{class:"token expression"}},[t._v("e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message")]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example where we spend straight to our BDK based wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("handleEvent")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("bdkManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("testnet "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("regtest\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" script "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcastTransactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("localizedDescription"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.SpendableOutputs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("SpendableOutputs")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L802",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("SpendableOutputs")]),t._v(" bindings"),s("OutboundLink")],1)])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{409:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"closing-a-channel"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#closing-a-channel"}},[t._v("#")]),t._v(" Closing a Channel")]),t._v(" "),s("p",[t._v("Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs will be accepted on the given channel, and after additional timeout/the closing of all pending HTLCs, the channel will be closed on chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_channels")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("channel"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" channel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Channel not found"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example: Cooperative close")]),t._v("\nchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to close channel"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example: Unilateral close")]),t._v("\nchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("force_close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to close channel"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("close_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Result_NoneAPIErrorZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_NoneAPIErrorZ_Err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle error")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful close")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Add Channel Id in bytes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Add Counterparty Node Id in bytes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("closeChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" counterpartyNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Channel Closed")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("To claim Funds directly into a custom wallet like BDK wallet using a custom "),s("code",[t._v("KeysManager")]),t._v(" see the "),s("RouterLink",{attrs:{to:"/key_management/"}},[t._v("Key Management")]),t._v(" guide for more info.")],1),t._v(" "),s("h1",{attrs:{id:"spendableoutputs-event-handling"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spendableoutputs-event-handling"}},[t._v("#")]),t._v(" SpendableOutputs Event Handling")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputs")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// SpendableOutputDescriptors, of which outputs is a vec of, are critical to keep track")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// of! While a `StaticOutput` descriptor is just an output to a static, well-known key,")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// other descriptors are not currently ever regenerated for you by LDK. Once we return")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// from this method, the descriptor will be gone, and you may lose track of some funds.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Here we simply persist them to disk, with a background task running which will try")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// to spend them regularly (possibly duplicatively/RBF'ing them). These can just be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// treated as normal funds where possible - they are only spendable by us and there is")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// no rush to claim them.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" output "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("hex_utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hex_str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_secure_random_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note that if the type here changes our read code needs to change as well.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fs_store"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("PENDING_SPENDABLE_OUTPUT_DIR")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("encode")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example where we spend straight to our BDK based wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SpendableOutputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("outputs\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" OnchainWallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getNewAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" script "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("Address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("TxOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("arrayOf")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txOut"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u32Z"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("None"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("none")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_TransactionNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_TransactionNoneZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("arrayOf")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("plus")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n LDKBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Exception"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Error: ')]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("${")]),s("span",{pre:!0,attrs:{class:"token expression"}},[t._v("e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message")]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example where we spend straight to our BDK based wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("handleEvent")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" outputs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("bdkManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("testnet "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("regtest\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" script "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n ldkManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcastTransactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("error"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("localizedDescription"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.SpendableOutputs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("SpendableOutputs")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L802",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("SpendableOutputs")]),t._v(" bindings"),s("OutboundLink")],1)])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/45.cfb2e077.js b/assets/js/45.1321bae5.js similarity index 99% rename from assets/js/45.cfb2e077.js rename to assets/js/45.1321bae5.js index 8f7261c86..b5657fb50 100644 --- a/assets/js/45.cfb2e077.js +++ b/assets/js/45.1321bae5.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{411:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"connect-to-peers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#connect-to-peers"}},[t._v("#")]),t._v(" Connect to Peers")]),t._v(" "),s("p",[t._v("In this section you'll learn how to join the lightning network.")]),t._v(" "),s("p",[t._v("Firstly we need to have the ability to do high performance I/O operations. LDK provides default implementations for initializing all of your networking needs. If you are using Rust, you can use our simple socket handling library "),s("code",[t._v("lightning_net_tokio")]),t._v(". In Kotlin/Java you can use the "),s("code",[t._v("NioPeerHandler")]),t._v(" which uses Java's NIO I/O interface.")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for")]),t._v(": making peer connections, facilitating peer data to and from LDK")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// use LDK's sample networking module")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" listen_port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9735")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" listener "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("net"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TcpListener")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.0.0:{}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" listen_port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tcp_stream "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" listener"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("accept")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spawn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's supplied networking battery to facilitate inbound")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// connections.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setup_inbound")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n tcp_stream"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("into_std")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val nioPeerHandler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("nio_peer_handler\nval port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9777")]),t._v("\nnioPeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind_listener")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InetSocketAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerHandler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTCPPeerHandler")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9777")]),t._v("\npeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("Connections to other peers are established with "),s("code",[t._v("PeerManager")]),t._v(". You'll need to know the pubkey and address of another node that you want as a peer. Once the connection is established and the handshake is complete, "),s("code",[t._v("PeerManager")]),t._v(" will show the peer's pubkey in its list of peers.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect_outbound")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" connection_closed_future "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Box")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pin")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Make sure the connection is still established.")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("futures"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("poll!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Poll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ready")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Peer disconnected before handshake completed"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Poll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Wait for the handshake to complete.")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_peer_node_ids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("id"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleep")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_millis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to connect to peer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Connect and wait for the handshake to complete.")]),t._v("\n val address"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InetSocketAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("hostname"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n nioPeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pubkeyHex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5555")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The peer's pubkey will be present in the list of peer ids.")]),t._v("\n val peerManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peer_manager\n val peerNodeIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_peer_node_ids\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IOException")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failure when connecting to a peer.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Connect and wait for the handshake to complete.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" pubKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's pubKey as byte array")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's address")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's port")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" theirNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pubKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The peer's pubkey will be present in the list of peer ids.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peerManager\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerNodeIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPeerNodeIds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("PeerManager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("lightning-net-tokio")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("PeerManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/batteries/NioPeerHandler.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("NioPeerHandler")]),t._v(" bindings"),s("OutboundLink")],1),t._v(",\n"),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("PeerManager")]),t._v(" bindings"),s("OutboundLink")],1),t._v(",")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{410:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"connect-to-peers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#connect-to-peers"}},[t._v("#")]),t._v(" Connect to Peers")]),t._v(" "),s("p",[t._v("In this section you'll learn how to join the lightning network.")]),t._v(" "),s("p",[t._v("Firstly we need to have the ability to do high performance I/O operations. LDK provides default implementations for initializing all of your networking needs. If you are using Rust, you can use our simple socket handling library "),s("code",[t._v("lightning_net_tokio")]),t._v(". In Kotlin/Java you can use the "),s("code",[t._v("NioPeerHandler")]),t._v(" which uses Java's NIO I/O interface.")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for")]),t._v(": making peer connections, facilitating peer data to and from LDK")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// use LDK's sample networking module")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" listen_port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9735")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" listener "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("net"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TcpListener")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.0.0:{}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" listen_port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tcp_stream "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" listener"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("accept")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spawn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's supplied networking battery to facilitate inbound")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// connections.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("setup_inbound")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n tcp_stream"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("into_std")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val nioPeerHandler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("nio_peer_handler\nval port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9777")]),t._v("\nnioPeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind_listener")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InetSocketAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerHandler "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTCPPeerHandler")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9777")]),t._v("\npeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("Connections to other peers are established with "),s("code",[t._v("PeerManager")]),t._v(". You'll need to know the pubkey and address of another node that you want as a peer. Once the connection is established and the handshake is complete, "),s("code",[t._v("PeerManager")]),t._v(" will show the peer's pubkey in its list of peers.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_net_tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect_outbound")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" connection_closed_future "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Box")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pin")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Make sure the connection is still established.")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("futures"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("poll!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" connection_closed_future"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Poll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ready")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Peer disconnected before handshake completed"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Poll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Wait for the handshake to complete.")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_peer_node_ids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("id"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sleep")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_millis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Failed to connect to peer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Connect and wait for the handshake to complete.")]),t._v("\n val address"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SocketAddress")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InetSocketAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("hostname"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n nioPeerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pubkeyHex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5555")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The peer's pubkey will be present in the list of peer ids.")]),t._v("\n val peerManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peer_manager\n val peerNodeIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_peer_node_ids\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IOException")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failure when connecting to a peer.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Connect and wait for the handshake to complete.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" pubKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's pubKey as byte array")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's address")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" port "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to retrieve peer's port")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("connect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" port"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" theirNodeId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pubKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The peer's pubkey will be present in the list of peer ids.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peerManager\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerNodeIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" peerManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPeerNodeIds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("PeerManager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("lightning-net-tokio")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("PeerManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/batteries/NioPeerHandler.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("NioPeerHandler")]),t._v(" bindings"),s("OutboundLink")],1),t._v(",\n"),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("PeerManager")]),t._v(" bindings"),s("OutboundLink")],1),t._v(",")])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/46.8d3e64cb.js b/assets/js/46.7b38fa74.js similarity index 99% rename from assets/js/46.8d3e64cb.js rename to assets/js/46.7b38fa74.js index 1a1a4a7b4..823c9bd85 100644 --- a/assets/js/46.8d3e64cb.js +++ b/assets/js/46.7b38fa74.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{415:function(t,n,s){"use strict";s.r(n);var a=s(7),e=Object(a.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"handling-events"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#handling-events"}},[t._v("#")]),t._v(" Handling Events")]),t._v(" "),n("p",[t._v("LDK requires that you handle many different events throughout your app's life cycle. You can learn more by reading about our event-driven "),n("RouterLink",{attrs:{to:"/introduction/architecture/"}},[t._v("architecture")]),t._v(".")],1),t._v(" "),n("p",[t._v("To start handling events in your application, run:")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("util"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("events"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the event handler passed to BackgroundProcessor::start")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rejected_by_dest "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FundingGenerationReady")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" org"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Event\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentSent"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentFailed"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FundingGenerationReady"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Create a funding tx to be broadcast")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-Swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentSent")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentFailed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsFundingGenerationReady")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Create a funding tx to be broadcast")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[t._v("References: "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/events/enum.Event.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),n("code",[t._v("Event")]),t._v(" docs"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),n("code",[t._v("Event")]),t._v(" bindings"),n("OutboundLink")],1)])],1)}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{411:function(t,n,s){"use strict";s.r(n);var a=s(7),e=Object(a.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"handling-events"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#handling-events"}},[t._v("#")]),t._v(" Handling Events")]),t._v(" "),n("p",[t._v("LDK requires that you handle many different events throughout your app's life cycle. You can learn more by reading about our event-driven "),n("RouterLink",{attrs:{to:"/introduction/architecture/"}},[t._v("architecture")]),t._v(".")],1),t._v(" "),n("p",[t._v("To start handling events in your application, run:")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("util"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("events"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the event handler passed to BackgroundProcessor::start")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rejected_by_dest "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FundingGenerationReady")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" org"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Event\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentSent"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentFailed"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FundingGenerationReady"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Create a funding tx to be broadcast")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-Swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentSent")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentFailed")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsFundingGenerationReady")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Create a funding tx to be broadcast")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[t._v("References: "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/events/enum.Event.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),n("code",[t._v("Event")]),t._v(" docs"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),n("code",[t._v("Event")]),t._v(" bindings"),n("OutboundLink")],1)])],1)}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/47.da1c1809.js b/assets/js/47.12527657.js similarity index 99% rename from assets/js/47.da1c1809.js rename to assets/js/47.12527657.js index d80691e68..01dfe8b1c 100644 --- a/assets/js/47.da1c1809.js +++ b/assets/js/47.12527657.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{413:function(t,s,n){"use strict";n.r(s);var a=n(7),e=Object(a.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"getting-started"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting started")]),t._v(" "),s("p",[t._v("Welcome to the Lightning Development Kit documentation!")]),t._v(" "),s("p",[t._v("If you have any questions about anything related to LDK, feel free to ask our community on "),s("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions",target:"_blank",rel:"noopener noreferrer"}},[t._v("GitHub Discussions"),s("OutboundLink")],1),t._v(" or join us on "),s("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[t._v("Discord"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),s("p",[t._v("Add LDK to a project by configuring the respective config files:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-toml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-toml"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Add the following dependencies to your cargo.toml and replace {VERSION} with the version number you want to use.")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token table class-name"}},[t._v("dependencies")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("features")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"max_level_trace"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-block-sync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("features")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rpc-client"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-invoice")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-net-tokio")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-persister")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-background-processor")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-rapid-gossip-sync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\nFor Gradle, add the following dependency to your build.gradle and replace {VERSION} with\nthe version number you want to use.\n*/")]),t._v("\n\ndependencies "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n implementation 'org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("lightningdevkit"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("VERSION")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("'\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* To include the LDK Kotlin bindings in an Android project download the latest binary from https://github.com/lightningdevkit/ldk-garbagecollected/releases and place it in your libs directory.\nThen add to your build.gradle file:\n*/")]),t._v("\n\ndependencies "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n implementation "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fileTree")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("include"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token char"}},[t._v("'*.aar'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dir"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token char"}},[t._v("'libs'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("Example usage after installation is complete:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Installing LDK Swift")]),t._v(" "),s("p",[t._v("Add ldk-swift package using the Swift Package Manager.")]),t._v(" "),s("p",[t._v("To import the package, use: "),s("code",[t._v("import LightningDevKit")])])])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{412:function(t,s,n){"use strict";n.r(s);var a=n(7),e=Object(a.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"getting-started"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting started")]),t._v(" "),s("p",[t._v("Welcome to the Lightning Development Kit documentation!")]),t._v(" "),s("p",[t._v("If you have any questions about anything related to LDK, feel free to ask our community on "),s("a",{attrs:{href:"https://github.com/orgs/lightningdevkit/discussions",target:"_blank",rel:"noopener noreferrer"}},[t._v("GitHub Discussions"),s("OutboundLink")],1),t._v(" or join us on "),s("a",{attrs:{href:"https://discord.gg/xaYE3pDQpm",target:"_blank",rel:"noopener noreferrer"}},[t._v("Discord"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("h2",{attrs:{id:"installation"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),s("p",[t._v("Add LDK to a project by configuring the respective config files:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-toml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-toml"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Add the following dependencies to your cargo.toml and replace {VERSION} with the version number you want to use.")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token table class-name"}},[t._v("dependencies")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("features")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"max_level_trace"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-block-sync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("features")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rpc-client"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-invoice")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-net-tokio")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-persister")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-background-processor")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("lightning-rapid-gossip-sync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key property"}},[t._v("version")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("VERSION"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\nFor Gradle, add the following dependency to your build.gradle and replace {VERSION} with\nthe version number you want to use.\n*/")]),t._v("\n\ndependencies "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n implementation 'org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("lightningdevkit"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("VERSION")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("'\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* To include the LDK Kotlin bindings in an Android project download the latest binary from https://github.com/lightningdevkit/ldk-garbagecollected/releases and place it in your libs directory.\nThen add to your build.gradle file:\n*/")]),t._v("\n\ndependencies "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n implementation "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fileTree")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("include"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token char"}},[t._v("'*.aar'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dir"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token char"}},[t._v("'libs'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("Example usage after installation is complete:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Installing LDK Swift")]),t._v(" "),s("p",[t._v("Add ldk-swift package using the Swift Package Manager.")]),t._v(" "),s("p",[t._v("To import the package, use: "),s("code",[t._v("import LightningDevKit")])])])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/48.44152f4f.js b/assets/js/48.ef78afe4.js similarity index 98% rename from assets/js/48.44152f4f.js rename to assets/js/48.ef78afe4.js index 558428397..d2fa07eff 100644 --- a/assets/js/48.44152f4f.js +++ b/assets/js/48.ef78afe4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{414:function(t,n,e){"use strict";e.r(n);var r=e(7),o=Object(r.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"building-a-node-with-ldk"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#building-a-node-with-ldk"}},[t._v("#")]),t._v(" Building a Node with LDK")]),t._v(" "),n("h2",{attrs:{id:"learn-how-to-build-a-basic-ldk-node-from-scratch"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#learn-how-to-build-a-basic-ldk-node-from-scratch"}},[t._v("#")]),t._v(" Learn how to build a basic LDK node from scratch")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),n("p",[t._v("For an integrated example of an LDK node in Rust, see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample Node"),n("OutboundLink")],1)])]),t._v(" "),n("p",[t._v("The following tutorials will show you how to build the simplest lightning node using LDK, that fufills the following tasks:")]),t._v(" "),n("ol",[n("li",[n("strong",[t._v("Connecting to Peers")])]),t._v(" "),n("li",[n("strong",[t._v("Opening Channels")])]),t._v(" "),n("li",[n("strong",[t._v("Sending Payments")])]),t._v(" "),n("li",[n("strong",[t._v("Receiving Payments")])]),t._v(" "),n("li",[n("strong",[t._v("Closing Channels")])])]),t._v(" "),n("h3",{attrs:{id:"foundational-components"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#foundational-components"}},[t._v("#")]),t._v(" Foundational Components")]),t._v(" "),n("p",[t._v("Let's start by looking at the core components we'll need to make this node work for the tasks we outlined above.")]),t._v(" "),n("ol",[n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("ChannelManager")]),n("OutboundLink")],1),t._v(", to open and close channels.")]),t._v(" "),n("li",[t._v("A networking stack (https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/index.html), for establishing TCP/IP connections to other nodes on the lightning network.")]),t._v(" "),n("li",[t._v("Payments & routing, ability to create and pay invoices.")])]),t._v(" "),n("p",[t._v("To make the above work we also need to setup a series of supporting modules, including:")]),t._v(" "),n("ol",[n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("FeeEstimator")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/logger/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Logger")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A Transaction "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Broadcaster")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.NetworkGraph.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("NetworkGraph")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/persist/trait.Persister.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Persister")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("An "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/trait.EventHandler.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("EventHandler")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A Transaction "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Filter")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("ChainMonitor")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("KeysManager")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Scorer")]),n("OutboundLink")],1)])])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{413:function(t,n,e){"use strict";e.r(n);var r=e(7),o=Object(r.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"building-a-node-with-ldk"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#building-a-node-with-ldk"}},[t._v("#")]),t._v(" Building a Node with LDK")]),t._v(" "),n("h2",{attrs:{id:"learn-how-to-build-a-basic-ldk-node-from-scratch"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#learn-how-to-build-a-basic-ldk-node-from-scratch"}},[t._v("#")]),t._v(" Learn how to build a basic LDK node from scratch")]),t._v(" "),n("div",{staticClass:"custom-block tip"},[n("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),n("p",[t._v("For an integrated example of an LDK node in Rust, see the "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample Node"),n("OutboundLink")],1)])]),t._v(" "),n("p",[t._v("The following tutorials will show you how to build the simplest lightning node using LDK, that fufills the following tasks:")]),t._v(" "),n("ol",[n("li",[n("strong",[t._v("Connecting to Peers")])]),t._v(" "),n("li",[n("strong",[t._v("Opening Channels")])]),t._v(" "),n("li",[n("strong",[t._v("Sending Payments")])]),t._v(" "),n("li",[n("strong",[t._v("Receiving Payments")])]),t._v(" "),n("li",[n("strong",[t._v("Closing Channels")])])]),t._v(" "),n("h3",{attrs:{id:"foundational-components"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#foundational-components"}},[t._v("#")]),t._v(" Foundational Components")]),t._v(" "),n("p",[t._v("Let's start by looking at the core components we'll need to make this node work for the tasks we outlined above.")]),t._v(" "),n("ol",[n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("ChannelManager")]),n("OutboundLink")],1),t._v(", to open and close channels.")]),t._v(" "),n("li",[t._v("A networking stack (https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/index.html), for establishing TCP/IP connections to other nodes on the lightning network.")]),t._v(" "),n("li",[t._v("Payments & routing, ability to create and pay invoices.")])]),t._v(" "),n("p",[t._v("To make the above work we also need to setup a series of supporting modules, including:")]),t._v(" "),n("ol",[n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("FeeEstimator")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/logger/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Logger")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A Transaction "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Broadcaster")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.NetworkGraph.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("NetworkGraph")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/persist/trait.Persister.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Persister")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("An "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/trait.EventHandler.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("EventHandler")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A Transaction "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Filter")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("ChainMonitor")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("KeysManager")]),n("OutboundLink")],1)]),t._v(" "),n("li",[t._v("A "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/index.html",target:"_blank",rel:"noopener noreferrer"}},[n("code",[t._v("Scorer")]),n("OutboundLink")],1)])])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/49.7323f45a.js b/assets/js/49.8335f985.js similarity index 99% rename from assets/js/49.7323f45a.js rename to assets/js/49.8335f985.js index 644e7e239..2132f7723 100644 --- a/assets/js/49.7323f45a.js +++ b/assets/js/49.8335f985.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{416:function(t,a,n){"use strict";n.r(a);var s=n(7),e=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"opening-a-channel"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#opening-a-channel"}},[t._v("#")]),t._v(" Opening a Channel")]),t._v(" "),a("p",[t._v("Channels are the basic building blocks of the Lightning Network. With channels, you can transact not only with your immediate peers but with others on the network. Let's explore how to open a channel with LDK.")]),t._v(" "),a("p",[t._v("Now that you have a peer, you can open a channel with them using "),a("code",[t._v("ChannelManager")]),t._v(". You'll need the peer's pubkey as before along with:")]),t._v(" "),a("ul",[a("li",[t._v("the amount in sats to use when funding the channel,")]),t._v(" "),a("li",[t._v("any msats to push to your peer,")]),t._v(" "),a("li",[t._v("an id which is given back in the "),a("code",[t._v("FundingGenerationReady")]),t._v(" event,")]),t._v(" "),a("li",[t._v("an optional "),a("code",[t._v("UserConfig")]),t._v(" for overriding "),a("code",[t._v("ChannelManager")]),t._v(" defaults")])]),t._v(" "),a("p",[t._v("Channels can be announced to the network or can remain private, which is controlled via "),a("code",[t._v("UserConfig::announced_channel")]),t._v(".")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amount "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" push_msat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channel_options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelConfig")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" announced_channel"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_channel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" push_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EVENT: initiated channel with peer {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to open channel: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-kotlin extra-class"},[a("pre",{pre:!0,attrs:{class:"language-kotlin"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" amount "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100_000L")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" pushMsat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1_000L")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" userChannelId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UInt128")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Random"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextLong")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// public aka announced channel")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" userConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" UserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelHandshakeConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ChannelHandshakeConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelHandshakeConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_announced_channel "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\nuserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_channel_handshake_config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelHandshakeConfig\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" createChannelResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_channel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n pubKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userConfig\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100000")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" userId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytesArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UUID")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uuid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// public aka announced channel")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" userConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelHandshakeConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelHandshakeConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("setAnnouncedChannel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("val"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nuserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("setChannelHandshakeConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("val"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" createChannelResults "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createChannel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\ttheirNetworkKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pubKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tchannelValueSatoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tpushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tuserChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\toverrideConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userConfig\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("h1",{attrs:{id:"fundinggenerationready-event-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fundinggenerationready-event-handling"}},[t._v("#")]),t._v(" FundingGenerationReady Event Handling")]),t._v(" "),a("p",[t._v("At this point, an outbound channel has been initiated with your peer and it will appear in "),a("code",[t._v("ChannelManager::list_channels")]),t._v(". However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a "),a("code",[t._v("FundingGenerationReady")]),t._v(" event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),a("p",[t._v("Remember that the funding transaction must only spend "),a("a",{attrs:{href:"https://bitcoinops.org/en/topics/segregated-witness/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SegWit"),a("OutboundLink")],1),t._v(" inputs.")])]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FundingGenerationReady")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\ttemporary_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tchannel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\toutput_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tuser_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build_tx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\tbuilder\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("add_recipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fee_rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("enable_rbf")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\tbuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\t \t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" finalized "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignOptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" raw_tx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" finalized"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extract_tx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FundingGenerationReady")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val fundingSpk "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("output_script\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("size "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("34")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("output_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("funding_transaction_generated")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("temporary_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("counterparty_node_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n rawTx\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\nfun "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Long")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tval scriptListUByte"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UByte")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("asList")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval outputScript "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scriptListUByte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxBuilder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("addRecipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("outputScript"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toULong")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("feeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4.0F")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("serialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsFundingGenerationReady")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" script "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rawOutputScript"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getOutputScript")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelValue "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getChannelValueSatoshis")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValue"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fundingTransactionGenerated")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t\ttemporaryChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTemporaryChannelId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tcounterpartyNodeId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getCounterpartyNodeId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tfundingTransaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" rawTx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("serialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxBuilder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("addRecipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("feeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("satPerVbyte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4.0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" signOptions"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/events/enum.Event.html#variant.FundingGenerationReady",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("FundingGenerationReady")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L95",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java "),a("code",[t._v("FundingGenerationReady")]),t._v(" bindings"),a("OutboundLink")],1)]),t._v(" "),a("h1",{attrs:{id:"broadcasting-the-funding-transaction"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#broadcasting-the-funding-transaction"}},[t._v("#")]),t._v(" Broadcasting the Funding Transaction")]),t._v(" "),a("p",[t._v("After crafting the funding transaction you'll need to send it to the Bitcoin network where it will hopefully be mined and added to the blockchain. You'll need to watch this transaction and wait for a minimum of 6 confirmations before the channel is ready to use.")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcast_transactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" server_url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DEFAULT_ESPLORA_SERVER_URL")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tx_sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraSyncClient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("server_url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraBlockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("BDK_CLIENT_STOP_GAP")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_concurrency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("BDK_CLIENT_CONCURRENCY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tx_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_in_place")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\tlocked_runtime\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_ref")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_on")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("log_error!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to broadcast transaction: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\nobject "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("BroadcasterInterfaceInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("out "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\tval esploraURL "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"esplora url"')]),t._v("\n val blockchainConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Esplora")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("esploraURL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\tval blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n txs"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("let "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" transactions "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CoroutineScope")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Dispatchers")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("IO")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("launch "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n transactions"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forEach "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" txByteArray "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v("\n val uByteArray "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" txByteArray"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n val transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("uByteArray"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toList")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("LDKTAG")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"The raw transaction broadcast is: ${txByteArray.toHex()}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IllegalStateException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Broadcaster attempted to broadcast a null transaction"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyBroacaster")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcastTransactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" esploraURL "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-literal"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"esploraUrl"')])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" esploraConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("baseUrl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" esploraURL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proxy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" concurrency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stopGap"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" timeout"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchainConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockchainConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("esplora")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" esploraConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" blockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" txs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transactionBytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" tx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-literal"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to broadcast transaction: ')]),a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("\\(")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[t._v("error"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("localizedDescription")]),a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("BroadcasterInterface")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("BroadcasterInterface")]),t._v(" bindings"),a("OutboundLink")],1)]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Keep LDK in sync")]),t._v(" "),a("p",[t._v("Remember if you are restarting and have open channels then you should "),a("RouterLink",{attrs:{to:"/building-a-node-with-ldk/setting-up-a-channel-manager/#sync-channelmonitors-and-channelmanager-to-chain-tip"}},[t._v("let LDK know about the latest channel state.")])],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{414:function(t,a,n){"use strict";n.r(a);var s=n(7),e=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"opening-a-channel"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#opening-a-channel"}},[t._v("#")]),t._v(" Opening a Channel")]),t._v(" "),a("p",[t._v("Channels are the basic building blocks of the Lightning Network. With channels, you can transact not only with your immediate peers but with others on the network. Let's explore how to open a channel with LDK.")]),t._v(" "),a("p",[t._v("Now that you have a peer, you can open a channel with them using "),a("code",[t._v("ChannelManager")]),t._v(". You'll need the peer's pubkey as before along with:")]),t._v(" "),a("ul",[a("li",[t._v("the amount in sats to use when funding the channel,")]),t._v(" "),a("li",[t._v("any msats to push to your peer,")]),t._v(" "),a("li",[t._v("an id which is given back in the "),a("code",[t._v("FundingGenerationReady")]),t._v(" event,")]),t._v(" "),a("li",[t._v("an optional "),a("code",[t._v("UserConfig")]),t._v(" for overriding "),a("code",[t._v("ChannelManager")]),t._v(" defaults")])]),t._v(" "),a("p",[t._v("Channels can be announced to the network or can remain private, which is controlled via "),a("code",[t._v("UserConfig::announced_channel")]),t._v(".")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amount "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" push_msat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1_000")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channel_options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelConfig")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" announced_channel"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_channel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" push_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EVENT: initiated channel with peer {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to open channel: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-kotlin extra-class"},[a("pre",{pre:!0,attrs:{class:"language-kotlin"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" amount "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100_000L")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" pushMsat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1_000L")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" userChannelId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UInt128")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Random"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("nextLong")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// public aka announced channel")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" userConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" UserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelHandshakeConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ChannelHandshakeConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelHandshakeConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_announced_channel "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\nuserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_channel_handshake_config "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelHandshakeConfig\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" createChannelResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_channel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n pubKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userConfig\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100000")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" userId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytesArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("UUID")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uuid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// public aka announced channel")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" userConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelHandshakeConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelHandshakeConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("setAnnouncedChannel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("val"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nuserConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("setChannelHandshakeConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("val"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" createChannelResults "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createChannel")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\ttheirNetworkKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pubKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tchannelValueSatoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tpushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pushMsat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tuserChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\toverrideConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userConfig\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("h1",{attrs:{id:"fundinggenerationready-event-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fundinggenerationready-event-handling"}},[t._v("#")]),t._v(" FundingGenerationReady Event Handling")]),t._v(" "),a("p",[t._v("At this point, an outbound channel has been initiated with your peer and it will appear in "),a("code",[t._v("ChannelManager::list_channels")]),t._v(". However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a "),a("code",[t._v("FundingGenerationReady")]),t._v(" event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.")]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Note")]),t._v(" "),a("p",[t._v("Remember that the funding transaction must only spend "),a("a",{attrs:{href:"https://bitcoinops.org/en/topics/segregated-witness/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SegWit"),a("OutboundLink")],1),t._v(" inputs.")])]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FundingGenerationReady")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\ttemporary_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tchannel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\toutput_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tuser_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" builder "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build_tx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\tbuilder\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("add_recipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fee_rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("enable_rbf")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\tbuilder"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\t \t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" finalized "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignOptions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" raw_tx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" finalized"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extract_tx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FundingGenerationReady")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val fundingSpk "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("output_script\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("size "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("34")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" fundingSpk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channel_value_satoshis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("output_script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("funding_transaction_generated")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("temporary_channel_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("counterparty_node_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n rawTx\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\nfun "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Long")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tval scriptListUByte"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UByte")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("asList")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval outputScript "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scriptListUByte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxBuilder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("addRecipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("outputScript"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toULong")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("feeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4.0F")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\tval rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("serialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// After the peer responds with an `accept_channel` message, an")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Event.FundingGenerationReady event will be generated.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsFundingGenerationReady")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" script "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rawOutputScript"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getOutputScript")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelValue "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getChannelValueSatoshis")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValue"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rawTx "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fundingTransactionGenerated")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t\ttemporaryChannelId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getTemporaryChannelId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tcounterpartyNodeId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getCounterpartyNodeId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tfundingTransaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" rawTx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("serialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Generate the funding transaction for the channel based on the channel amount")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// The following uses BDK (Bitcoin Dev Kit) for on-chain logic")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("buildFundingTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxBuilder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("addRecipient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" script"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("feeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("satPerVbyte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4.0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("finish")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("wallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" onchainWallet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sign")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" signOptions"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("psbt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("extractTx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/events/enum.Event.html#variant.FundingGenerationReady",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("FundingGenerationReady")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L95",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java "),a("code",[t._v("FundingGenerationReady")]),t._v(" bindings"),a("OutboundLink")],1)]),t._v(" "),a("h1",{attrs:{id:"broadcasting-the-funding-transaction"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#broadcasting-the-funding-transaction"}},[t._v("#")]),t._v(" Broadcasting the Funding Transaction")]),t._v(" "),a("p",[t._v("After crafting the funding transaction you'll need to send it to the Bitcoin network where it will hopefully be mined and added to the blockchain. You'll need to watch this transaction and wait for a minimum of 6 confirmations before the channel is ready to use.")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcast_transactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" server_url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DEFAULT_ESPLORA_SERVER_URL")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tx_sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraSyncClient")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("server_url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraBlockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("BDK_CLIENT_STOP_GAP")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_concurrency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("BDK_CLIENT_CONCURRENCY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tx_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("task"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_in_place")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\tlocked_runtime\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_ref")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_on")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("move")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("log_error!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to broadcast transaction: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\nobject "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("BroadcasterInterfaceInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("out "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\tval esploraURL "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"esplora url"')]),t._v("\n val blockchainConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Esplora")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("esploraURL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\tval blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n txs"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("let "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" transactions "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("CoroutineScope")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Dispatchers")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("IO")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("launch "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n transactions"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forEach "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" txByteArray "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v("\n val uByteArray "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" txByteArray"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n val transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("uByteArray"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toList")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("LDKTAG")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"The raw transaction broadcast is: ${txByteArray.toHex()}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throw")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IllegalStateException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Broadcaster attempted to broadcast a null transaction"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyBroacaster")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcastTransactions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" esploraURL "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-literal"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"esploraUrl"')])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" esploraConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EsploraConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("baseUrl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" esploraURL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" proxy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" concurrency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stopGap"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" timeout"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchainConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockchainConfig")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("esplora")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" esploraConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" blockchain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Blockchain")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" blockchainConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" txs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" transaction "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transactionBytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" tx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" blockchain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" transaction"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-literal"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to broadcast transaction: ')]),a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("\\(")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[t._v("error"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("localizedDescription")]),a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("BroadcasterInterface")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("BroadcasterInterface")]),t._v(" bindings"),a("OutboundLink")],1)]),t._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[t._v("Keep LDK in sync")]),t._v(" "),a("p",[t._v("Remember if you are restarting and have open channels then you should "),a("RouterLink",{attrs:{to:"/building-a-node-with-ldk/setting-up-a-channel-manager/#sync-channelmonitors-and-channelmanager-to-chain-tip"}},[t._v("let LDK know about the latest channel state.")])],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/6.647cd57c.js b/assets/js/5.4068247b.js similarity index 95% rename from assets/js/6.647cd57c.js rename to assets/js/5.4068247b.js index 7d53c08e1..177959efe 100644 --- a/assets/js/6.647cd57c.js +++ b/assets/js/5.4068247b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[6,8],{251:function(t,e){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},254:function(t,e,n){},255:function(t,e,n){},256:function(t,e,n){},257:function(t,e,n){},258:function(t,e,n){"use strict";n(254)},260:function(t,e,n){"use strict";var r={name:"PostMeta",props:["post"],filters:{capitalize:n(251).capitalize}},i=(n(258),n(7)),s=Object(i.a)(r,(function(){var t=this,e=t._self._c;return e("p",{staticClass:"meta"},[t._v("\n By\n\n "),t._l(t.post.frontmatter.authors,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/author/"+n}},[t._v(t._s(n))]),r!=t.post.frontmatter.authors.length-1?e("span",[t._v(", ")]):t._e()],1)})),t._v("\n\n on\n\n "+t._s(new Date(t.post.frontmatter.date).getMonth()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getDate()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getFullYear())+"\n\n - Tags:\n\n "),t._l(t.post.frontmatter.tags,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/tags/"+n}},[t._v(t._s(t._f("capitalize")(n)))]),r!=t.post.frontmatter.tags.length-1?[t._v(", ")]:t._e()],2)}))],2)}),[],!1,null,"0f148fb8",null);e.a=s.exports},265:function(t,e,n){"use strict";n(255)},266:function(t,e,n){"use strict";n(256)},267:function(t,e,n){var r=n(104),i=n(97),s=n(268),o=n(272);t.exports=function(t,e){if(null==t)return{};var n=r(o(t),(function(t){return[t]}));return e=i(e),s(t,n,(function(t,n){return e(t,n[0])}))}},268:function(t,e,n){var r=n(52),i=n(269),s=n(47);t.exports=function(t,e,n){for(var o=-1,a=e.length,u={};++o({comp:null}),computed:{page(){return this.$pagination.paginationIndex+1}},mounted(){n.e(4).then(n.t.bind(null,377,7)).then(t=>{this.comp=t.default})},methods:{clickCallback(t){const e=this.$pagination.getSpecificPageLink(t-1);this.$router.push(e)}}}),o=(n(265),n(7)),a=Object(o.a)(s,(function(){var t=this._self._c;return this.comp?t(this.comp,{tag:"component",attrs:{value:this.page,"page-count":this.$pagination.length,"click-handler":this.clickCallback,"prev-text":this.$pagination.prevText,"next-text":this.$pagination.nextText,"container-class":"pagination","page-class":"page-item"}}):this._e()}),[],!1,null,null,null).exports,u=(n(266),Object(o.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"pagination simple-pagination"},[t.$pagination.hasPrev?e("router-link",{attrs:{to:t.$pagination.prevLink}},[t._v("\n "+t._s(t.$pagination.prevText)+"\n ")]):t._e(),t._v(" "),t.$pagination.hasNext?e("router-link",{attrs:{to:t.$pagination.nextLink}},[t._v("\n "+t._s(t.$pagination.nextText)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports,n(24)),p=n.n(u),c=n(267),l=n.n(c),f={props:{title:{type:[String,Function],required:!1},issueId:{type:[String,Number],required:!1},options:{type:Object,required:!1},shortname:{type:String,required:!1},identifier:{type:String,required:!1},url:{type:String,required:!1},remote_auth_s3:{type:String,required:!1},api_key:{type:String,required:!1},sso_config:{type:Object,required:!1},language:{type:String,required:!1}},computed:{propsWithoutEmptyProperties(){return l()(this.$props,p.a)},commentProps(){return Object.assign({},this.propsWithoutEmptyProperties,this.$frontmatter.comment)},vssueProps(){return Object.assign({title:this.$page.title},this.commentProps)},disqusProps(){return Object.assign({identifier:this.$page.key},this.commentProps)}}},g=(Object(o.a)(f,(function(){var t=this._self._c;return"vssue"===this.$service.comment.service?t("Vssue",this._b({},"Vssue",this.vssueProps,!1)):"disqus"===this.$service.comment.service?t("Disqus",this._b({},"Disqus",this.disqusProps,!1)):this._e()}),[],!1,null,null,null).exports,n(251)),v={name:"IndexPost",components:{LayoutWrap:r.a,Pagination:a,PostMeta:i.a},props:["items","title"],computed:{posts(){return this.items||this.$pagination.pages.sort((t,e)=>new Date(e.frontmatter.date)-new Date(t.frontmatter.date))}},filters:{capitalize:g.capitalize}},h=(n(278),Object(o.a)(v,(function(){var t=this,e=t._self._c;return e("LayoutWrap",[e("main",{staticClass:"page"},[e("div",{staticClass:"theme-default-content"},[e("h1",[t._v(t._s(t.title||"Blog"))]),t._v(" "),t._l(t.posts,(function(n){return e("div",{key:n.path},[e("h2",{staticClass:"index-post-title"},[e("router-link",{attrs:{to:n.path}},[t._v(t._s(n.title||n.frontmatter.title))])],1),t._v(" "),e("PostMeta",{attrs:{post:n}}),t._v(" "),n.frontmatter.coverImage?e("router-link",{attrs:{to:n.path}},[e("img",{staticClass:"cover-image",attrs:{src:n.frontmatter.coverImage}})]):t._e(),t._v(" "),e("hr")],1)})),t._v(" "),t.$pagination.length>1?e("Pagination"):t._e()],2)])])}),[],!1,null,"073f78a2",null));e.default=h.exports},380:function(t,e,n){"use strict";n.r(e);var r={name:"DirectoryPagination",components:{IndexPost:n(281).default}},i=n(7),s=Object(i.a)(r,(function(){return(0,this._self._c)("IndexPost")}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[5,8],{251:function(t,e){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},254:function(t,e,n){},255:function(t,e,n){},256:function(t,e,n){},257:function(t,e,n){},258:function(t,e,n){"use strict";n(254)},260:function(t,e,n){"use strict";var r={name:"PostMeta",props:["post"],filters:{capitalize:n(251).capitalize}},i=(n(258),n(7)),s=Object(i.a)(r,(function(){var t=this,e=t._self._c;return e("p",{staticClass:"meta"},[t._v("\n By\n\n "),t._l(t.post.frontmatter.authors,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/author/"+n}},[t._v(t._s(n))]),r!=t.post.frontmatter.authors.length-1?e("span",[t._v(", ")]):t._e()],1)})),t._v("\n\n on\n\n "+t._s(new Date(t.post.frontmatter.date).getMonth()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getDate()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getFullYear())+"\n\n - Tags:\n\n "),t._l(t.post.frontmatter.tags,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/tags/"+n}},[t._v(t._s(t._f("capitalize")(n)))]),r!=t.post.frontmatter.tags.length-1?[t._v(", ")]:t._e()],2)}))],2)}),[],!1,null,"0f148fb8",null);e.a=s.exports},265:function(t,e,n){"use strict";n(255)},266:function(t,e,n){"use strict";n(256)},267:function(t,e,n){var r=n(104),i=n(97),s=n(268),o=n(272);t.exports=function(t,e){if(null==t)return{};var n=r(o(t),(function(t){return[t]}));return e=i(e),s(t,n,(function(t,n){return e(t,n[0])}))}},268:function(t,e,n){var r=n(52),i=n(269),s=n(47);t.exports=function(t,e,n){for(var o=-1,a=e.length,u={};++o({comp:null}),computed:{page(){return this.$pagination.paginationIndex+1}},mounted(){n.e(4).then(n.t.bind(null,375,7)).then(t=>{this.comp=t.default})},methods:{clickCallback(t){const e=this.$pagination.getSpecificPageLink(t-1);this.$router.push(e)}}}),o=(n(265),n(7)),a=Object(o.a)(s,(function(){var t=this._self._c;return this.comp?t(this.comp,{tag:"component",attrs:{value:this.page,"page-count":this.$pagination.length,"click-handler":this.clickCallback,"prev-text":this.$pagination.prevText,"next-text":this.$pagination.nextText,"container-class":"pagination","page-class":"page-item"}}):this._e()}),[],!1,null,null,null).exports,u=(n(266),Object(o.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"pagination simple-pagination"},[t.$pagination.hasPrev?e("router-link",{attrs:{to:t.$pagination.prevLink}},[t._v("\n "+t._s(t.$pagination.prevText)+"\n ")]):t._e(),t._v(" "),t.$pagination.hasNext?e("router-link",{attrs:{to:t.$pagination.nextLink}},[t._v("\n "+t._s(t.$pagination.nextText)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports,n(24)),p=n.n(u),c=n(267),l=n.n(c),f={props:{title:{type:[String,Function],required:!1},issueId:{type:[String,Number],required:!1},options:{type:Object,required:!1},shortname:{type:String,required:!1},identifier:{type:String,required:!1},url:{type:String,required:!1},remote_auth_s3:{type:String,required:!1},api_key:{type:String,required:!1},sso_config:{type:Object,required:!1},language:{type:String,required:!1}},computed:{propsWithoutEmptyProperties(){return l()(this.$props,p.a)},commentProps(){return Object.assign({},this.propsWithoutEmptyProperties,this.$frontmatter.comment)},vssueProps(){return Object.assign({title:this.$page.title},this.commentProps)},disqusProps(){return Object.assign({identifier:this.$page.key},this.commentProps)}}},g=(Object(o.a)(f,(function(){var t=this._self._c;return"vssue"===this.$service.comment.service?t("Vssue",this._b({},"Vssue",this.vssueProps,!1)):"disqus"===this.$service.comment.service?t("Disqus",this._b({},"Disqus",this.disqusProps,!1)):this._e()}),[],!1,null,null,null).exports,n(251)),v={name:"IndexPost",components:{LayoutWrap:r.a,Pagination:a,PostMeta:i.a},props:["items","title"],computed:{posts(){return this.items||this.$pagination.pages.sort((t,e)=>new Date(e.frontmatter.date)-new Date(t.frontmatter.date))}},filters:{capitalize:g.capitalize}},h=(n(278),Object(o.a)(v,(function(){var t=this,e=t._self._c;return e("LayoutWrap",[e("main",{staticClass:"page"},[e("div",{staticClass:"theme-default-content"},[e("h1",[t._v(t._s(t.title||"Blog"))]),t._v(" "),t._l(t.posts,(function(n){return e("div",{key:n.path},[e("h2",{staticClass:"index-post-title"},[e("router-link",{attrs:{to:n.path}},[t._v(t._s(n.title||n.frontmatter.title))])],1),t._v(" "),e("PostMeta",{attrs:{post:n}}),t._v(" "),n.frontmatter.coverImage?e("router-link",{attrs:{to:n.path}},[e("img",{staticClass:"cover-image",attrs:{src:n.frontmatter.coverImage}})]):t._e(),t._v(" "),e("hr")],1)})),t._v(" "),t.$pagination.length>1?e("Pagination"):t._e()],2)])])}),[],!1,null,"073f78a2",null));e.default=h.exports},378:function(t,e,n){"use strict";n.r(e);var r={name:"DirectoryPagination",components:{IndexPost:n(282).default}},i=n(7),s=Object(i.a)(r,(function(){return(0,this._self._c)("IndexPost")}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/5.a6d25585.js b/assets/js/5.a6d25585.js deleted file mode 100644 index ad7695b4c..000000000 --- a/assets/js/5.a6d25585.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{253:function(A,t){A.exports="data:image/png;base64,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"},280:function(A,t){A.exports="data:image/png;base64,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"},286:function(A,t){A.exports="data:image/png;base64,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"},304:function(A,t){A.exports="data:image/png;base64,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"},305:function(A,t){A.exports="data:image/png;base64,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"},306:function(A,t,g){A.exports=g.p+"assets/img/blue-wallet.fb035b79.png"},307:function(A,t){A.exports="data:image/png;base64,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"},308:function(A,t,g){A.exports=g.p+"assets/img/kumuly.8dee19a3.png"},309:function(A,t){A.exports="data:image/png;base64,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"},310:function(A,t){A.exports="data:image/png;base64,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"},311:function(A,t,g){A.exports=g.p+"assets/img/alby.d8538ae1.svg"},312:function(A,t,g){A.exports=g.p+"assets/img/atomic.ffecd305.png"},313:function(A,t,g){A.exports=g.p+"assets/img/hydranet.e412d0cf.png"},314:function(A,t,g){A.exports=g.p+"assets/img/cash-app-logo.86558a78.png"},315:function(A,t,g){A.exports=g.p+"assets/img/aciedo.37b33a98.svg"},316:function(A,t){A.exports="data:image/png;base64,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"},317:function(A,t){A.exports="data:image/png;base64,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"},318:function(A,t,g){A.exports=g.p+"assets/img/lndk.abb38b97.png"},319:function(A,t){A.exports="data:image/png;base64,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"},320:function(A,t){A.exports="data:image/png;base64,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"},321:function(A,t,g){A.exports=g.p+"assets/img/teos.e5cd86a3.png"},322:function(A,t,g){A.exports=g.p+"assets/img/vls.322e82ca.png"},323:function(A,t){A.exports="data:image/png;base64,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"},421:function(A,t,g){"use strict";g.r(t);var a=g(7),s=Object(a.a)({},(function(){var A=this,t=A._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":A.$parent.slotKey}},[t("h1",{staticClass:"more-cases-heading"},[A._v("\n Meet the projects building with LDK\n")]),A._v(" "),t("CodeSwitcher",{attrs:{languages:{all:"All",mobile:"Mobile",web:"Web",desktop:"Desktop",custodial:"Custodial",infra:"Infrastructure",misc:"Misc"}},scopedSlots:A._u([{key:"mobile",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[t("img",{attrs:{src:g(304)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[A._v("10101")])]),A._v(" "),t("p",[A._v("An on and off-chain wallet infused with trading")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[t("img",{attrs:{src:g(305)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[A._v("Bitkit")])]),A._v(" "),t("p",[A._v("The ultimate bitcoin toolkit, take charge of your digital life")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bluewallet.io/",target:"_blank"}},[t("img",{attrs:{src:g(306)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bluewallet.io/",target:"_blank"}},[A._v("Blue Wallet")])]),A._v(" "),t("p",[A._v("A radically simple and powerful bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[t("img",{attrs:{src:g(307)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[A._v("EttaWallet")])]),A._v(" "),t("p",[A._v("A simple open-source wallet with a strong bias toward usability, accessibility, and UX")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[t("img",{attrs:{src:g(308)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[A._v("Kumuly")])]),A._v(" "),t("p",[A._v("Colombian-based mobile bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(286)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[t("img",{attrs:{src:g(309)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[A._v("Velas")])]),A._v(" "),t("p",[A._v("A way to integrate Lightning into websites, mobile applications, and more")])])])]},proxy:!0},{key:"web",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(310)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[A._v("Mutiny")])]),A._v(" "),t("p",[A._v("A web-first unstoppable bitcoin wallet for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[t("img",{attrs:{src:g(311)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[A._v("Alby Hub")])]),A._v(" "),t("p",[A._v("With its own lightning node, connecting you to numerous applications")])])])]},proxy:!0},{key:"desktop",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[t("img",{attrs:{src:g(312)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[A._v("AtomicDEX")])]),A._v(" "),t("p",[A._v("A multi-coin wallet, bridge, and DEX rolled into one app")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[t("img",{attrs:{src:g(313)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[A._v("Hydranet")])]),A._v(" "),t("p",[A._v("A layer 3 decentralized exchange, allowing trading with native tokens between blockchains")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(286)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])])])]},proxy:!0},{key:"custodial",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[t("img",{attrs:{src:g(314)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[A._v("Cash App")])]),A._v(" "),t("p",[A._v("Send and spend, bank, and buy stocks or bitcoin")])])])]},proxy:!0},{key:"infra",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[t("img",{attrs:{src:g(315)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[A._v("Aciedo")])]),A._v(" "),t("p",[A._v("A financial infrastructure suite for developers and users")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[t("img",{attrs:{src:g(316)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[A._v("c=")])]),A._v(" "),t("p",[A._v("Tools and services that connect people to the Lightning Network")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[t("img",{attrs:{src:g(317)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[A._v("kuutamo")])]),A._v(" "),t("p",[A._v("A turn-key, end-to-end solution for running self-hosted nodes, anywhere")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[t("img",{attrs:{src:g(318)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[A._v("LNDK")])]),A._v(" "),t("p",[A._v("A standalone daemon that aims to externally implement BOLT 12 functionality for LND")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[t("img",{attrs:{src:g(319)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[A._v("Lexe")])]),A._v(" "),t("p",[A._v("Managed non-custodial Lightning nodes inside secure hardware")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[t("img",{attrs:{src:g(280)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[A._v("Lightspark")])]),A._v(" "),t("p",[A._v("Enterprise-grade, fast, secure payments on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[t("img",{attrs:{src:g(320)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[A._v("Sensei")])]),A._v(" "),t("p",[A._v("A Lightning node implementation for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[t("img",{attrs:{src:g(321)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[A._v("TEOS")])]),A._v(" "),t("p",[A._v("A bitcoin watchtower with a specific focus on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[t("img",{attrs:{src:g(322)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[A._v("VLS")])]),A._v(" "),t("p",[A._v("Separates Lightning private keys and security rule validation from nodes, into a discrete signing device")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[t("img",{attrs:{src:g(323)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[A._v("Voltage")])]),A._v(" "),t("p",[A._v("Enterprise-grade infrastructure for the Lightning Network")])])])]},proxy:!0},{key:"misc",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[A._v("Gossiper")])]),A._v(" "),t("p",[A._v("Lightning Gossip Ingestion")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[A._v("The Hidden LN")])]),A._v(" "),t("p",[A._v("Probes the Lightning Network for the detection of private channels")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[A._v("ldk-sample with Tor")])]),A._v(" "),t("p",[A._v("An experimentation with tor that adapts the ldk-sample node")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[A._v("rgb-lightning-node")])]),A._v(" "),t("p",[A._v("LN node based on ldk-sample supporting RGB assets")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[A._v("rust-dlc")])]),A._v(" "),t("p",[A._v("A Rust library for working with Discreet Log Contracts")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[A._v("uMlando")])]),A._v(" "),t("p",[A._v("An educational Android demo wallet")])])])]},proxy:!0},{key:"all",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[t("img",{attrs:{src:g(304)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[A._v("10101")])]),A._v(" "),t("p",[A._v("An on and off-chain wallet infused with trading")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[t("img",{attrs:{src:g(315)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[A._v("Aciedo")])]),A._v(" "),t("p",[A._v("A financial infrastructure suite for developers and users")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[t("img",{attrs:{src:g(311)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[A._v("Alby Hub")])]),A._v(" "),t("p",[A._v("With its own lightning node, connecting you to numerous apps")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[t("img",{attrs:{src:g(312)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[A._v("AtomicDEX")])]),A._v(" "),t("p",[A._v("A multi-coin wallet, bridge, and DEX rolled into one app")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[t("img",{attrs:{src:g(305)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[A._v("Bitkit")])]),A._v(" "),t("p",[A._v("The ultimate bitcoin toolkit, take charge of your digital life")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bluewallet.io/",target:"_blank"}},[t("img",{attrs:{src:g(306)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bluewallet.io/",target:"_blank"}},[A._v("Blue Wallet")])]),A._v(" "),t("p",[A._v("A radically simple and powerful bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[t("img",{attrs:{src:g(316)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[A._v("c=")])]),A._v(" "),t("p",[A._v("Tools and services that connect people to the Lightning Network")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[t("img",{attrs:{src:g(314)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[A._v("Cash App")])]),A._v(" "),t("p",[A._v("Send and spend, bank, and buy stocks or bitcoin")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[t("img",{attrs:{src:g(307)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[A._v("EttaWallet")])]),A._v(" "),t("p",[A._v("A simple open-source wallet with a strong bias toward usability, accessibility, and UX")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[A._v("Gossiper")])]),A._v(" "),t("p",[A._v("Lightning Gossip Ingestion")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[t("img",{attrs:{src:g(313)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[A._v("Hydranet")])]),A._v(" "),t("p",[A._v("A layer 3 decentralized exchange, allowing trading with native tokens between blockchains")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[t("img",{attrs:{src:g(308)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[A._v("Kumuly")])]),A._v(" "),t("p",[A._v("Colombian-based mobile bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[t("img",{attrs:{src:g(317)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[A._v("kuutamo")])]),A._v(" "),t("p",[A._v("A turn-key, end-to-end solution for running self-hosted nodes, anywhere")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[A._v("ldk-sample with Tor")])]),A._v(" "),t("p",[A._v("An experimentation with tor that adapts the ldk-sample node")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[t("img",{attrs:{src:g(319)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[A._v("Lexe")])]),A._v(" "),t("p",[A._v("Managed non-custodial Lightning nodes inside secure hardware")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[t("img",{attrs:{src:g(280)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[A._v("Lightspark")])]),A._v(" "),t("p",[A._v("Enterprise-grade, fast, secure payments on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[t("img",{attrs:{src:g(318)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[A._v("LNDK")])]),A._v(" "),t("p",[A._v("A standalone daemon that aims to externally implement BOLT 12 functionality for LND")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(286)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(310)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[A._v("Mutiny")])]),A._v(" "),t("p",[A._v("A web-first unstoppable bitcoin wallet for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[A._v("rgb-lightning-node")])]),A._v(" "),t("p",[A._v("LN node based on ldk-sample supporting RGB assets")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[A._v("rust-dlc")])]),A._v(" "),t("p",[A._v("A Rust library for working with Discreet Log Contracts")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[t("img",{attrs:{src:g(320)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[A._v("Sensei")])]),A._v(" "),t("p",[A._v("A Lightning node implementation for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[t("img",{attrs:{src:g(321)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[A._v("TEOS")])]),A._v(" "),t("p",[A._v("A bitcoin watchtower with a specific focus on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[A._v("The Hidden LN")])]),A._v(" "),t("p",[A._v("Probes the Lightning Network for the detection of private channels")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[A._v("uMlando")])]),A._v(" "),t("p",[A._v("An educational Android demo wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[t("img",{attrs:{src:g(309)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[A._v("Velas")])]),A._v(" "),t("p",[A._v("A way to integrate Lightning into websites, mobile applications, and more")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[t("img",{attrs:{src:g(322)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[A._v("VLS")])]),A._v(" "),t("p",[A._v("Separates Lightning private keys and security rule validation from nodes, into a discrete signing device")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[t("img",{attrs:{src:g(323)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[A._v("Voltage")])]),A._v(" "),t("p",[A._v("Enterprise-grade infrastructure for the Lightning Network")])])])]},proxy:!0}])})],1)}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/50.44d01ea5.js b/assets/js/50.7b910e14.js similarity index 99% rename from assets/js/50.44d01ea5.js rename to assets/js/50.7b910e14.js index 6d2d3d9c2..6ad33ed9b 100644 --- a/assets/js/50.44d01ea5.js +++ b/assets/js/50.7b910e14.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{417:function(t,n,a){"use strict";a.r(n);var s=a(7),e=Object(s.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"receiving-payments"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#receiving-payments"}},[t._v("#")]),t._v(" Receiving Payments")]),t._v(" "),n("p",[t._v("To receive a payment, you'll need to create an invoice of your own with an\namount and description. "),n("code",[t._v("ChannelManager")]),t._v(" contains the remaining information\nneeded for the invoice. Use the provided utility to generate an invoice and\nregister a pending payment in "),n("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("utils"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_invoice_from_channelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"description"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n expiry_secs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inv"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SUCCESS: generated invoice: {}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" inv"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n inv\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to create invoice: {:?}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_hash "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentHash")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_hash")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_byte_array")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\ninbound_payments"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payments"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentInfo")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n secret"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_secret")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n status"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HTLCStatus")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MillisatAmount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" description "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"description"')])]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" amtMsat"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("3000000")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" UtilMethods"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_invoice_from_channelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKCurrency_Regtest"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u64Z"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amtMsat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n description"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("300")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u16Z"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("144")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" invoiceResult "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_Bolt11InvoiceSignOrCreationErrorZ"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_Bolt11InvoiceSignOrCreationErrorZ_OK"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" encodedInvoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoiceResult"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("createInvoiceFromChannelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelmanager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channelManager"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeSigner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" myKeysManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("asNodeSigner")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n network"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amtMsat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n description"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string-literal"}},[n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Test Invoice"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n invoiceExpiryDeltaSecs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expiry"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n minFinalCltvExpiryDelta"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ninvoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("toStr")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[t._v("While it is possible to create an invoice without using the utility,\n"),n("code",[t._v("ChannelManager")]),t._v(" will reject any incoming HTLCs for unregistered payments to\nprotect your privacy. In this case, use either "),n("code",[t._v("create_inbound_payment")]),t._v(" or\n"),n("code",[t._v("create_inbound_payment_for_hash")]),t._v(" to register a payment with "),n("code",[t._v("ChannelManager")]),t._v("\nbefore creating the invoice with the returned payment hash and/or secret.\nYou might also opt to for "),n("code",[t._v("inbound_payment")]),t._v(", useful for generating invoices for "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.PhantomKeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("phantom node payments"),n("OutboundLink")],1),t._v(" without a ChannelManager.")]),t._v(" "),n("h1",{attrs:{id:"paymentclaimable-event-handling"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#paymentclaimable-event-handling"}},[t._v("#")]),t._v(" PaymentClaimable Event Handling")]),t._v(" "),n("p",[t._v("As with sending a payment, LDK will generate an event once a payment is\nreceived. It is your responsibility to handle the "),n("code",[t._v("PaymentClaimable")]),t._v(" event by\nusing "),n("code",[t._v("ChannelManager")]),t._v(" to release the preimage and claim the funds.")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimable")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n purpose"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amount_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n receiver_node_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n via_channel_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n via_user_channel_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n claim_deadline"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n onion_fields"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n counterparty_skimmed_fee_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\nEVENT: received payment from payment hash {} of {} millisatoshis"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("print!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"> "')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("io"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("stdout")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("flush")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_preimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" purpose "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvoicePayment")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpontaneousPayment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channel_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentClaimable"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payment_hash "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" purpose "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("purpose "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" InvoicePayment\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" paymentPreimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("purpose"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payment_preimage "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Option_ThirtyTwoBytesZ"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Some"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("some\n\n channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentPreimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentClaimedEvent "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentClaimable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentPreimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentClaimedEvent"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsInvoicePayment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPaymentPreimage")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claimFunds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentPreimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentPreimage"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[n("strong",[t._v("References:")]),t._v(" "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentClaimable",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),n("code",[t._v("PaymentClaimable")]),t._v(" docs"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L261",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),n("code",[t._v("PaymentClaimable")]),t._v(" bindings"),n("OutboundLink")],1)])],1)}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{416:function(t,n,a){"use strict";a.r(n);var s=a(7),e=Object(s.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"receiving-payments"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#receiving-payments"}},[t._v("#")]),t._v(" Receiving Payments")]),t._v(" "),n("p",[t._v("To receive a payment, you'll need to create an invoice of your own with an\namount and description. "),n("code",[t._v("ChannelManager")]),t._v(" contains the remaining information\nneeded for the invoice. Use the provided utility to generate an invoice and\nregister a pending payment in "),n("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("utils"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_invoice_from_channelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"description"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n expiry_secs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inv"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SUCCESS: generated invoice: {}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" inv"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n inv\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to create invoice: {:?}"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_hash "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentHash")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_hash")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_byte_array")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\ninbound_payments"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payments"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentInfo")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n secret"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_secret")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n status"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HTLCStatus")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Pending")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MillisatAmount")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amt_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" description "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"description"')])]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" amtMsat"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("3000000")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" UtilMethods"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("create_invoice_from_channelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKCurrency_Regtest"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u64Z"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("amtMsat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n description"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("300")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Option_u16Z"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("144")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" invoiceResult "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_Bolt11InvoiceSignOrCreationErrorZ"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_Bolt11InvoiceSignOrCreationErrorZ_OK"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" encodedInvoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoiceResult"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_str")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("createInvoiceFromChannelmanager")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelmanager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("channelManager"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeSigner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" myKeysManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("asNodeSigner")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("logger"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n network"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" currency"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amtMsat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" amount"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n description"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string-literal"}},[n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Test Invoice"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n invoiceExpiryDeltaSecs"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" expiry"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n minFinalCltvExpiryDelta"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\ninvoice"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("toStr")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[t._v("While it is possible to create an invoice without using the utility,\n"),n("code",[t._v("ChannelManager")]),t._v(" will reject any incoming HTLCs for unregistered payments to\nprotect your privacy. In this case, use either "),n("code",[t._v("create_inbound_payment")]),t._v(" or\n"),n("code",[t._v("create_inbound_payment_for_hash")]),t._v(" to register a payment with "),n("code",[t._v("ChannelManager")]),t._v("\nbefore creating the invoice with the returned payment hash and/or secret.\nYou might also opt to for "),n("code",[t._v("inbound_payment")]),t._v(", useful for generating invoices for "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.PhantomKeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("phantom node payments"),n("OutboundLink")],1),t._v(" without a ChannelManager.")]),t._v(" "),n("h1",{attrs:{id:"paymentclaimable-event-handling"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#paymentclaimable-event-handling"}},[t._v("#")]),t._v(" PaymentClaimable Event Handling")]),t._v(" "),n("p",[t._v("As with sending a payment, LDK will generate an event once a payment is\nreceived. It is your responsibility to handle the "),n("code",[t._v("PaymentClaimable")]),t._v(" event by\nusing "),n("code",[t._v("ChannelManager")]),t._v(" to release the preimage and claim the funds.")]),t._v(" "),n("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[n("div",{staticClass:"language-rust extra-class"},[n("pre",{pre:!0,attrs:{class:"language-rust"}},[n("code",[n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentClaimable")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n purpose"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n amount_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n receiver_node_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n via_channel_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n via_user_channel_id"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n claim_deadline"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n onion_fields"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n counterparty_skimmed_fee_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" _"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"\\nEVENT: received payment from payment hash {} of {} millisatoshis"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n payment_hash"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" amount_msat"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("print!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"> "')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("io"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("stdout")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("flush")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_preimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" purpose "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvoicePayment")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpontaneousPayment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channel_manager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payment_preimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[n("div",{staticClass:"language-kotlin extra-class"},[n("pre",{pre:!0,attrs:{class:"language-kotlin"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentClaimable"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payment_hash "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" purpose "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("purpose "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" InvoicePayment\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" paymentPreimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("purpose"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payment_preimage "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Option_ThirtyTwoBytesZ"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Some"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("some\n\n channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claim_funds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentPreimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[n("div",{staticClass:"language-swift extra-class"},[n("pre",{pre:!0,attrs:{class:"language-swift"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentClaimedEvent "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentClaimable")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentPreimage "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentClaimedEvent"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPurpose")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsInvoicePayment")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPaymentPreimage")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token omit keyword"}},[t._v("_")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("claimFunds")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentPreimage"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentPreimage"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),n("p",[n("strong",[t._v("References:")]),t._v(" "),n("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentClaimable",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),n("code",[t._v("PaymentClaimable")]),t._v(" docs"),n("OutboundLink")],1),t._v(", "),n("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L261",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),n("code",[t._v("PaymentClaimable")]),t._v(" bindings"),n("OutboundLink")],1)])],1)}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/51.84fb33a5.js b/assets/js/51.cf60934f.js similarity index 99% rename from assets/js/51.84fb33a5.js rename to assets/js/51.cf60934f.js index ee53886b4..561c85510 100644 --- a/assets/js/51.84fb33a5.js +++ b/assets/js/51.cf60934f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{418:function(t,a,s){"use strict";s.r(a);var n=s(7),e=Object(n.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"sending-payments"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#sending-payments"}},[t._v("#")]),t._v(" Sending Payments")]),t._v(" "),a("p",[t._v("Lightning payments are used to pay invoices, which are typically encoded as a\nstring in accordance with BOLT 11. After parsing the invoice, you'll need to\nfind a route from your node to the recipient and then make the payment using\n"),a("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Parse the invoice.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("encoded_invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to parse invoice"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amt_pico_btc "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("amount_pico_btc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: invalid invoice: must contain amount to pay"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amt_msat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" amt_pico_btc "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payer_pubkey "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_our_node_id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" router"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network_graph"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payee_pubkey "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("recover_payee_pub_key")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payee_features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cloned")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" first_hops "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_usable_channels")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" last_hops "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("route_hints")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" final_cltv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("min_final_cltv_expiry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Find a route and send the payment.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" route "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("router"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_route")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payer_pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payee_pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payee_features"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("first_hops"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("collect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("last_hops"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tamt_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" final_cltv"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to find route"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_hash "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentHash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_hash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("into_inner")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_secret "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_secret")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cloned")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nchannel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("route"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payment_secret"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to send payment"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Get an invoice from the recipient/payee")]),t._v("\nval invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("recipientInvoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval invoiceResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice as "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_Bolt11InvoiceParseOrSemanticErrorZ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_Bolt11InvoiceParseOrSemanticErrorZ_OK")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\nval paymentParams "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UtilMethods")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_parameters_from_invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoiceResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval paymentParamsResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentParams as "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_C3Tuple_ThirtyTwoBytesRecipientOnionFieldsRouteParametersZNoneZ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_C3Tuple_ThirtyTwoBytesRecipientOnionFieldsRouteParametersZNoneZ_OK")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n\nval paymentHash "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_a\nval recipientOnion "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_b\nval paymentId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_a\nval routeParams "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_c\n\nval res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("attempts")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Payment success")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoiceStr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get an invoice from the payee")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" parsedInvoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromStr")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceStr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoiceVal "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" parsedInvoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoicePaymentResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentParametersFromInvoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceVal"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("guard")]),t._v(" invoicePaymentResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentParametersFromInvoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceVal"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentHash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendPayment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n retryStrategy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithTimeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Payment Sent")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("h1",{attrs:{id:"paymentsent-paymentfailed-event-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#paymentsent-paymentfailed-event-handling"}},[t._v("#")]),t._v(" PaymentSent & PaymentFailed Event Handling")]),t._v(" "),a("p",[t._v("An event is generated once a payment has completed. Successful payments result\nin a "),a("code",[t._v("PaymentSent")]),t._v(" event with the preimage of the payment hash. Be sure to look\nout for a "),a("code",[t._v("PaymentFailed")]),t._v(" event, if the payment fails for some reason, and act\naccordingly.")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the event handler passed to BackgroundProcessor::start")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rejected_by_dest "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the `handleEvent` method of ChannelManagerPersister implementation")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentSent")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentFailed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the `handleEvent` method of ChannelManagerPersister implementation")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentSentEvent "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentSent")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentFailedEvent "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentFailed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentSent",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PaymentSent")]),t._v(" docs"),a("OutboundLink")],1),t._v(","),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentFailed",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PaymentFailed")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L464",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PaymentSent")]),t._v(" bindings"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L512",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PaymentFailed")]),t._v(" bindings"),a("OutboundLink")],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{415:function(t,a,s){"use strict";s.r(a);var n=s(7),e=Object(n.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"sending-payments"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#sending-payments"}},[t._v("#")]),t._v(" Sending Payments")]),t._v(" "),a("p",[t._v("Lightning payments are used to pay invoices, which are typically encoded as a\nstring in accordance with BOLT 11. After parsing the invoice, you'll need to\nfind a route from your node to the recipient and then make the payment using\n"),a("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Parse the invoice.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("encoded_invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to parse invoice"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amt_pico_btc "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("amount_pico_btc")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: invalid invoice: must contain amount to pay"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" amt_msat "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" amt_pico_btc "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payer_pubkey "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_our_node_id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" router"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network_graph"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payee_pubkey "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("recover_payee_pub_key")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payee_features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("features")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cloned")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" first_hops "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("list_usable_channels")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" last_hops "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("route_hints")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" final_cltv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("min_final_cltv_expiry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Find a route and send the payment.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" route "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("router"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_route")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payer_pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payee_pubkey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payee_features"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("first_hops"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("collect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("last_hops"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tamt_msat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" final_cltv"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to find route"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_hash "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentHash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_hash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("into_inner")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payment_secret "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_secret")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cloned")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nchannel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("route"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("payment_secret"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: failed to send payment"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Get an invoice from the recipient/payee")]),t._v("\nval invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("recipientInvoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval invoiceResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice as "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_Bolt11InvoiceParseOrSemanticErrorZ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_Bolt11InvoiceParseOrSemanticErrorZ_OK")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\nval paymentParams "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UtilMethods")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("payment_parameters_from_invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoiceResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval paymentParamsResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentParams as "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_C3Tuple_ThirtyTwoBytesRecipientOnionFieldsRouteParametersZNoneZ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_C3Tuple_ThirtyTwoBytesRecipientOnionFieldsRouteParametersZNoneZ_OK")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n\nval paymentHash "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_a\nval recipientOnion "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_b\nval paymentId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_a\nval routeParams "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" paymentParamsResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_c\n\nval res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_payment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Retry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("attempts")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("res"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Payment success")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoiceStr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// get an invoice from the payee")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" parsedInvoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bolt11Invoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromStr")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceStr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoiceVal "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" parsedInvoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" invoicePaymentResult "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentParametersFromInvoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceVal"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("guard")]),t._v(" invoicePaymentResult"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentParametersFromInvoice")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" invoiceVal"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" invoice"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("paymentHash")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendPayment")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentHash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" recipientOnion"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" paymentId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" routeParams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n retryStrategy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithTimeout")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Payment Sent")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("h1",{attrs:{id:"paymentsent-paymentfailed-event-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#paymentsent-paymentfailed-event-handling"}},[t._v("#")]),t._v(" PaymentSent & PaymentFailed Event Handling")]),t._v(" "),a("p",[t._v("An event is generated once a payment has completed. Successful payments result\nin a "),a("code",[t._v("PaymentSent")]),t._v(" event with the preimage of the payment hash. Be sure to look\nout for a "),a("code",[t._v("PaymentFailed")]),t._v(" event, if the payment fails for some reason, and act\naccordingly.")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the event handler passed to BackgroundProcessor::start")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" event "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentSent")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_preimage "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PaymentFailed")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" payment_hash"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rejected_by_dest "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the `handleEvent` method of ChannelManagerPersister implementation")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentSent")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("event is "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("PaymentFailed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// In the `handleEvent` method of ChannelManagerPersister implementation")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentSentEvent "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentSent")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle successful payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" paymentFailedEvent "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" event"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueAsPaymentFailed")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Handle failed payment")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentSent",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PaymentSent")]),t._v(" docs"),a("OutboundLink")],1),t._v(","),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentFailed",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PaymentFailed")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L464",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PaymentSent")]),t._v(" bindings"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L512",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PaymentFailed")]),t._v(" bindings"),a("OutboundLink")],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/52.e067b73b.js b/assets/js/52.3b333727.js similarity index 99% rename from assets/js/52.e067b73b.js rename to assets/js/52.3b333727.js index 1caf6334f..095f071cb 100644 --- a/assets/js/52.e067b73b.js +++ b/assets/js/52.3b333727.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{419:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"setting-up-a-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-a-channelmanager"}},[t._v("#")]),t._v(" Setting up a ChannelManager")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("ChannelManager")]),t._v(" is responsible for several tasks related to managing channel state. This includes keeping track of many channels, sending messages to appropriate channels, creating channels and more.")]),t._v(" "),s("h2",{attrs:{id:"adding-a-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#adding-a-channelmanager"}},[t._v("#")]),t._v(" Adding a ChannelManager")]),t._v(" "),s("p",[t._v("Adding a "),s("code",[t._v("ChannelManager")]),t._v(" to your application should look something like this:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("channelmanager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("entropy_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("node_signer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("signer_provider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n current_timestamp\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("batteries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ChannelManagerConstructor\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scoringParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n routerWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// optional")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructionParameters "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructionParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n entropySource"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asEntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeSigner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asNodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n enableP2PGossip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" scorer\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("There are a few dependencies needed to get this working. Let's walk through setting up each one so we can plug them into our "),s("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"initialize-the-feeestimator"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-feeestimator"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("FeeEstimator")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" estimating fees for on-chain transactions that LDK wants broadcasted.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Background")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch background feerate,")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Normal")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch normal feerate (~6 blocks)")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HighPriority")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch high priority feerate")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_estimator "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("object "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimatorInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_Background")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_Normal")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_HighPriority")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// return default fee rate")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\nval feeEstimator"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getEstSatPer1000Weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("253")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" feeEstimator "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ol",[s("li",[t._v("Fees must be returned in: satoshis per 1000 weight units")]),t._v(" "),s("li",[t._v("Fees must be no smaller than 253 (equivalent to 1 satoshi/vbyte, rounded up)")]),t._v(" "),s("li",[t._v("To reduce network traffic, you may want to cache fee results rather than\nretrieving fresh ones every time")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("FeeEstimator")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/FeeEstimator.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("FeeEstimator")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-router"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-router"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("Router")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" Finds a Route for a payment between the given payer and a payee.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" router "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultRouter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_secure_random_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringFeeParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" networkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" NetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Regtest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("P2PGossipSync")]),t._v(", "),s("code",[t._v("Logger")]),t._v(", "),s("code",[t._v("KeysManager")]),t._v(", "),s("code",[t._v("Scorer")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/router/trait.Router.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Router")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Router.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Router")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-logger"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-logger"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" LDK logging")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourLogger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Record")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" raw_log "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" log "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{} {:<5} [{}:{}] {}\\n"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OffsetDateTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now_utc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"%F %T"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("module_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("line"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n raw_log\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourLogger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LoggerInterface "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("record"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Record"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourLogger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Record")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Print and/or write the log to a file")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" you'll likely want to write the logs to a file for debugging purposes.")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/logger/trait.Logger.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Logger")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Logger.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Logger")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-broadcasterinterface"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-broadcasterinterface"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("BroadcasterInterface")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" broadcasting various transactions to the bitcoin network")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourTxBroadcaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" broadcaster "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourTxBroadcaster"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BroadcasterInterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("BroadcasterInterfaceInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("out")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txBroadcaster"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BroadcasterInterface "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" BroadcasterInterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourTxBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroacaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcastTransactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to broadcast a list of transactions")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" broadcaster "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroacaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("BroadcasterInterface")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("BroadcasterInterface")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-persist"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-persist"}},[t._v("#")]),t._v(" Initialize "),s("code",[t._v("Persist")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" persisting "),s("code",[t._v("ChannelMonitor")]),t._v("s, which contain crucial channel data, in a timely manner")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Sign")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Persist")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourPersister")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("persist_new_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateErr")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note that monitor.encode() will get you the ChannelMonitor as a")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Vec.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_persisted_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n update"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateErr")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourPersister"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Persist"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("PersistInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("persist_new_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" OutPoint"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("data")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MonitorUpdateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_NoneChannelMonitorUpdateErrZ"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_persisted_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" OutPoint"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" update"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitorUpdate"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("data")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n updateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MonitorUpdateId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_NoneChannelMonitorUpdateErrZ"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" persister"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Persist "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Persist"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourPersister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Persist")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("persistNewChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MonitorUpdateId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateStatus")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert the code to persist the ChannelMonitor to disk")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("updatePersistedChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" update"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MonitorUpdateId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateStatus")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert the code to persist either ChannelMonitor or ChannelMonitorUpdate to disk")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Using LDK Sample Filesystem Persistence Crate in Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FilesystemPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// import LDK sample persist crate")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FilesystemPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ldk_data_dir_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ul",[s("li",[s("code",[t._v("ChannelMonitor")]),t._v("s are objects which are capable of\nresponding to on-chain events for a given channel. Thus, you will have one\n"),s("code",[t._v("ChannelMonitor")]),t._v(" per channel. They are persisted in real-time and the "),s("code",[t._v("Persist")]),t._v("\nmethods will block progress on sending or receiving payments until they return.\nYou must ensure that "),s("code",[t._v("ChannelMonitor")]),t._v("s are durably persisted to disk before\nreturning or you may lose funds.")]),t._v(" "),s("li",[t._v("If you implement a custom persister, it's important to read the trait docs (linked in References) to make sure you satisfy the API requirements, particularly for "),s("code",[t._v("update_persisted_channel")])])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Persister")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Persist.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Persister")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"start-background-processing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#start-background-processing"}},[t._v("#")]),t._v(" Start Background Processing")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" running tasks periodically in the background to keep LDK operational.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" background_processor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BackgroundProcessor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("invoice_payer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("net_graph_msg_handler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("ChannelManager")]),t._v(", "),s("code",[t._v("ChainMonitor")]),t._v(", "),s("code",[t._v("PeerManager")]),t._v(", "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning-background-processor/*/lightning_background_processor/struct.BackgroundProcessor.html#method.start",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("BackgroundProcessor::Start")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"regularly-broadcast-node-announcement"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#regularly-broadcast-node-announcement"}},[t._v("#")]),t._v(" Regularly Broadcast Node Announcement")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if you have 1 or more public channels, you may need to announce your node and its channels occasionally. LDK will automatically announce channels when they are created, but there are no guarantees you have connected peers at that time or that your peers will propagate such announcements. The broader node-announcement message is not automatically broadcast.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" interval "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tinterval"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tick")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_node_announcement")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert your node's RGB color")]),t._v("\n\t\tnode_alias"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("vec!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ldk_announced_listen_addr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("Peer Manager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html#method.broadcast_node_announcement",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("PeerManager::broadcast_node_announcement")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-the-transaction-filter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-the-transaction-filter"}},[t._v("#")]),t._v(" Optional: Initialize the Transaction "),s("code",[t._v("Filter")])]),t._v(" "),s("p",[s("strong",[t._v("You must follow this step if:")]),t._v(" you are "),s("em",[t._v("not")]),t._v(" providing full blocks to LDK,\ni.e. if you're using BIP 157/158 or Electrum as your chain backend")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if you are not providing full blocks, LDK uses this\nobject to tell you what transactions and outputs to watch for on-chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Txid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("usize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("object "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FilterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\nval txFilter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("registerTx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" scriptPubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to watch this transaction")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("registerOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to watch for any transaction that spend this output")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" see the "),s("RouterLink",{attrs:{to:"/blockchain_data/introduction/"}},[t._v("Blockchain Data")]),t._v(" guide for more info")],1),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Filter")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Filter.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Filter")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-chainmonitor"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-chainmonitor"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("ChainMonitor")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" tracking one or more "),s("code",[t._v("ChannelMonitor")]),t._v("s and using them to monitor the chain for lighting transactions that are relevant to our node, and broadcasting transactions if need be.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Box")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as None or insert the Filter trait object")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chain_monitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as `null` or insert the Filter object.")]),t._v("\n\nval chainMonitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as `nil` or insert the Filter object.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chainMonitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n chainSource"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" persister\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" "),s("code",[t._v("Filter")]),t._v(" must be non-"),s("code",[t._v("None")]),t._v(" if you're using Electrum or BIP 157/158 as your chain backend")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("FeeEstimator")]),t._v(", "),s("code",[t._v("Logger")]),t._v(", "),s("code",[t._v("BroadcasterInterface")]),t._v(", "),s("code",[t._v("Persist")])]),t._v(" "),s("p",[s("strong",[t._v("Optional dependency:")]),t._v(" "),s("code",[t._v("Filter")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/struct.ChainMonitor.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ChainMonitor")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChainMonitor.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ChainMonitor")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-keysmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-keysmanager"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("KeysManager")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" providing keys for signing Lightning transactions")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_seed_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/keys_seed"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If we're restarting and already have a key seed, read it from disk. Else,")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// create a new one.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("fs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert_eq!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("len")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("copy_from_slice")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n key\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("thread_rng")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fill_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("File")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write_all")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to write node keys seed to disk"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sync_all")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to sync node keys seed to disk"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Unable to create keys seed file {}: {}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n key\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" cur "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val keySeed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nval keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n keySeed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to create seed with random bytes or if restarting, reload the seed from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ul",[s("li",[t._v("See the "),s("RouterLink",{attrs:{to:"/key_management/"}},[t._v("Key Management")]),t._v(" guide for more info")],1),t._v(" "),s("li",[t._v("Note that you must write the "),s("code",[t._v("key_seed")]),t._v(" you give to the "),s("code",[t._v("KeysManager")]),t._v(" on\nstartup to disk, and keep using it to initialize the "),s("code",[t._v("KeysManager")]),t._v(" every time\nyou restart. This "),s("code",[t._v("key_seed")]),t._v(" is used to derive your node's secret key (which\ncorresponds to its node pubkey) and all other secret key material.")]),t._v(" "),s("li",[t._v("The current time is part of the "),s("code",[t._v("KeysManager")]),t._v("'s parameters because it is used to derive\nrandom numbers from the seed where required, to ensure all random\ngeneration is unique across restarts.")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" random bytes")]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("KeysManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/KeysManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("KeysManager")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"read-channelmonitor-state-from-disk"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#read-channelmonitor-state-from-disk"}},[t._v("#")]),t._v(" Read "),s("code",[t._v("ChannelMonitor")]),t._v(" state from disk")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if LDK is restarting and has at least 1 channel, its "),s("code",[t._v("ChannelMonitor")]),t._v("s will need to be (1) fed to the "),s("code",[t._v("ChannelManager")]),t._v(" and (2) synced to chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's sample persister crate provided method")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_monitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_channelmonitors")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If you are using Electrum or BIP 157/158, you must call load_outputs_to_watch")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// on each ChannelMonitor to prepare for chain synchronization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" chan_mon "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chan_mon"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("load_outputs_to_watch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialize the hashmap where we'll store the `ChannelMonitor`s read from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This hashmap will later be given to the `ChannelManager` on initialization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" channelMonitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" arrayOf"),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nval channelMonitorList "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelMonitorFiles"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iterator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forEach "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val channelMonitorBytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hexStringToByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channelMonitorList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelMonitorBytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nchannelMonitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelMonitorList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTypedArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialize the array where we'll store the `ChannelMonitor`s read from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This array will later be given to the `ChannelManagerConstructor` on initialization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" allChannels "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to get a list of persisted channels")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" channel "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" allChannels "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelData "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Data")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("contentsOf"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelBytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelBytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("KeysManager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/channelmonitor/struct.ChannelMonitor.html#method.load_outputs_to_watch",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("load_outputs_to_watch")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-channelmanager"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("ChannelManager")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" managing channel state")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" user_config "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* RESTARTING */")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_manager_file "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("fs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("File")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/manager"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use the `ChannelMonitors` we read from disk.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_monitor_mut_references "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter_mut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channel_monitor_mut_references"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" read_args "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerReadArgs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channel_monitor_mut_references"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager_file"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" read_args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* FRESH CHANNELMANAGER */")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" best_blockhash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert the best blockhash you know of")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" best_chain_height "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert the height corresponding to best_blockhash")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chain_params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainParameters")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// substitute this with your network")]),t._v("\n best_block"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("best_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" best_chain_height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fresh_channel_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("entropy_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("node_signer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("signer_provider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n current_timestamp\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("best_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fresh_channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("serializedChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isNotEmpty")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Loading from disk (restarting)")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txFilter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringFeeParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fresh start")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringFeeParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" serializedChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("isEmpty "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelManagerSerialized"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelMonitorsSerialized"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraphArgument")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("instance")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" No methods should be called on "),s("code",[t._v("ChannelManager")]),t._v(" until\n"),s("em",[t._v("after")]),t._v(" the "),s("code",[t._v("ChannelMonitor")]),t._v("s and "),s("code",[t._v("ChannelManager")]),t._v(" are synced to the chain tip (next step).")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("KeysManager")]),t._v(", "),s("code",[t._v("FeeEstimator")]),t._v(", "),s("code",[t._v("ChainMonitor")]),t._v(", "),s("code",[t._v("BroadcasterInterface")]),t._v(", "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ChannelManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChannelManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ChannelManager")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"sync-channelmonitors-and-channelmanager-to-chain-tip"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#sync-channelmonitors-and-channelmanager-to-chain-tip"}},[t._v("#")]),t._v(" Sync "),s("code",[t._v("ChannelMonitor")]),t._v("s and "),s("code",[t._v("ChannelManager")]),t._v(" to chain tip")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" this step is only necessary if you're restarting and have open channels. This step ensures that LDK channel state is up-to-date with the bitcoin blockchain")]),t._v(" "),s("p",[s("strong",[t._v("Example:")])]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Full Blocks or BIP 157/158")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("init"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("poll"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UnboundedCache")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourChainBackend")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_header")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height_hint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHeaderData")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_best_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" block_source "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourChainBackend")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_listener_channel_monitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" cache "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UnboundedCache")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_tip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("poll"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ValidatedBlockHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_listeners "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("vec!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Listen")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("drain")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" outpoint "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_funding_txo")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n chain_listener_channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outpoint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" monitor_listener_info "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" chain_listener_channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter_mut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chain_listeners"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n monitor_listener_info"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" monitor_listener_info"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Listen")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Save the chain tip to be used in future steps")]),t._v("\nchain_tip "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("init"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("synchronize_listeners")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" block_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" cache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_listeners"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Electrum/Esplora")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transaction IDs to check the chain for un-confirmation.")]),t._v("\nval relevantTxIdsFromChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Confirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_relevant_txids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval relevantTxIdsFromChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Confirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_relevant_txids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval relevantTxIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relevantTxIdsFromChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" relevantTxIdsFromChainMonitor\n\nval unconfirmedTxs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid in unconfirmedTxs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transaction_unconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transaction_unconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transactions and outputs that were registered through the `Filter`")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// interface.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If any of these txs/outputs were confirmed on-chain, then:")]),t._v("\nval header"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert block header from the block with confirmed tx/output")]),t._v("\nval height"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert block height of `header`")]),t._v("\nval txIndex"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Long")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert tx index in block")]),t._v("\nval serializedTx"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert tx hex as byte array")]),t._v("\nval tx"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" serializedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Marshall all TwoTuples you built right above into an array")]),t._v("\nval txList "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" arrayOf"),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactions_confirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactions_confirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nval bestHeader"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nval bestHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_best_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_best_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Finally, tell LDK that chain sync is complete. This will also spawn several")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// background threads to handle networking and event processing.")]),t._v("\nchannelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chain_sync_completed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("customEventHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Electrum/Esplora")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transaction IDs to check the chain for un-confirmation.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" relevantTxIds1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRelevantTxids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" relevantTxIds2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRelevantTxids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" relevantTxIds1 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" relevantTxIds2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" unconfirmedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to find out from your chain source")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// if any of relevantTxIds have been reorged out")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// of the chain")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" txid "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" unconfirmedTx "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionUnconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionUnconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transactions and outputs that were registered through the `Filter` interface.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" confirmedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to find out from your chain source")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// if any of the `Filter` txs/outputs were confirmed")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// on-chain")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" txid "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" confirmedTx "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch header")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch height of the header")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch tx")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch tx index")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionsConfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txdata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionsConfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txdata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bestHeader "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch best header")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bestHeight "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch best height")]),t._v("\n\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bestBlockUpdated")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bestBlockUpdated")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Finally, tell LDK that chain sync is complete. This will also spawn several")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// background threads to handle networking and event processing.")]),t._v("\nchannelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chainSyncCompleted")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerPersister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("p",[t._v("There are 2 main options for synchronizing to chain on startup:")]),t._v(" "),s("p",[s("strong",[t._v("Full Blocks or BIP 157/158")])]),t._v(" "),s("p",[t._v("If you are connecting full blocks or using BIP 157/158, then it is recommended to use\nLDK's "),s("code",[t._v("lightning_block_sync")]),t._v(" crate as in the example above: the high-level steps that must be done for both "),s("code",[t._v("ChannelManager")]),t._v(" and each "),s("code",[t._v("ChannelMonitor")]),t._v(" are as follows:")]),t._v(" "),s("ol",[s("li",[t._v("Get the last blockhash that each object saw.\n"),s("ul",[s("li",[t._v("Receive the latest block hash when through "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManagerReadArgs.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("deserializtion"),s("OutboundLink")],1),t._v(" of the "),s("code",[t._v("ChannelManager")]),t._v(" via "),s("code",[t._v("read()")])]),t._v(" "),s("li",[t._v("Each "),s("code",[t._v("ChannelMonitor")]),t._v("'s is in "),s("code",[t._v("channel_manager.channel_monitors")]),t._v(", as the 2nd element in each tuple")])])]),t._v(" "),s("li",[t._v("For each object, if its latest known blockhash has been reorged out of the chain, then disconnect blocks using "),s("code",[t._v("channel_manager.as_Listen().block_disconnected(..)")]),t._v(" or "),s("code",[t._v("channel_monitor.block_disconnected(..)")]),t._v(" until you reach the last common ancestor with the main chain.")]),t._v(" "),s("li",[t._v("For each object, reconnect blocks starting from the common ancestor until it gets to your best known chain tip using "),s("code",[t._v("channel_manager.as_Listen().block_connected(..)")]),t._v(" and/or "),s("code",[t._v("channel_monitor.block_connected(..)")]),t._v(".")]),t._v(" "),s("li",[t._v("Call "),s("code",[t._v("channel_manager.chain_sync_completed(..)")]),t._v(" to complete the initial sync process.")])]),t._v(" "),s("p",[s("strong",[t._v("Electrum/Esplora")])]),t._v(" "),s("p",[t._v("Alternatively, you can use LDK's "),s("code",[t._v("lightning-transaction-sync")]),t._v(" crate. This provides utilities for syncing LDK via the transaction-based "),s("code",[t._v("Confirm")]),t._v(" interface.")]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-p2pgossipsync-or-rapidgossipsync"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-p2pgossipsync-or-rapidgossipsync"}},[t._v("#")]),t._v(" Optional: Initialize "),s("code",[t._v("P2PGossipSync or RapidGossipSync")])]),t._v(" "),s("p",[s("strong",[t._v("You must follow this step if:")]),t._v(" you need LDK to provide routes for sending payments (i.e. you are "),s("em",[t._v("not")]),t._v(" providing your own routes)")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" generating routes to send payments over")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" genesis "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("genesis_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_hash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/network_graph"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" genesis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" gossip_sync "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Access")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Send")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Sync")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val genesisBlock "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_genesis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval genesisBlockHash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("byteArrayToHex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("genesisBlock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_hash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nval serializedNetworkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read network graph bytes from file")]),t._v("\nval networkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("serializedNetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval p2pGossip "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option_AccessZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("none")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Network Graph exists, then read from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedNetworkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read Network Graph bytes from file")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" readResult "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ser"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedNetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" arg"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" readResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" readResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Network Graph does not exist, create a new one")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialise RGS")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rgs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RapidGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lastSync "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getLastRapidGossipSyncTimestamp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" snapshot "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" lastSync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("updateNetworkGraphNoStd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("updateData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" snapshot"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currentTimeUnix"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"RGS updated"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" snapshot "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use lastSyncTimeStamp as 0 for first Sync")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("updateNetworkGraphNoStd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("updateData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" snapshot"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currentTimeUnix"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"RGS initialized for the first time"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Get current snapshot from the RGS Server")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's RGS Server or use your own Server")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("URL")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("URL")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://rapidsync.lightningdevkit.org/snapshot/')]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("\\(")]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[t._v("lastSyncTimeStamp")]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use the url to get the data")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" this struct is not required if you are providing your own routes. It will be used internally in "),s("code",[t._v("ChannelManager")]),t._v(" to build a "),s("code",[t._v("NetworkGraph")]),t._v(". Network options include: "),s("code",[t._v("Mainnet")]),t._v(","),s("code",[t._v("Regtest")]),t._v(","),s("code",[t._v("Testnet")]),t._v(","),s("code",[t._v("Signet")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("Optional dependency:")]),t._v(" "),s("code",[t._v("Access")]),t._v(", a source of chain information. Recommended to be able to verify channels before adding them to the internal network graph.")]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.P2PGossipSync.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("P2PGossipSync")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Access.html",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("Access")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/P2PGossipSync.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("P2PGossipSync")]),t._v(" bindings"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("RapidGossipSync")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RapidGossipSync.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("RapidGossipSync")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-probabilistic-scorer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-probabilistic-scorer"}},[t._v("#")]),t._v(" Optional: Initialize "),s("code",[t._v("Probabilistic Scorer")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for")]),t._v(": to find a suitable payment path to reach the destination.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/network_graph"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/scorer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RwLock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_scorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("scorer_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("exists")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" scorerReaderResult "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("readBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerReaderResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerReaderResult "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_ProbabilisticScorerDecodeErrorZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_ProbabilisticScorerDecodeErrorZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Probabilistic Scorer loaded and running"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Couldn\'t load Probabilistic Scorer"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Creating a new Probabilistic Scorer"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Scorer exists, then read from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read Scorer bytes from file")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringDecayParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedProbabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n ser"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argC"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" serializedProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" res\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" score "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Scorer loaded")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MultiThreadedLockableScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Scorer does not exist, create a new one")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringDecayParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" score "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Scorer loaded")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MultiThreadedLockableScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("NetworkGraph")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/struct.ProbabilisticScorer.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ProbabilisticScorer")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ProbabilisticScorer.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ProbabilisticScorer")]),t._v(" docs"),s("OutboundLink")],1)])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{417:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"setting-up-a-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-a-channelmanager"}},[t._v("#")]),t._v(" Setting up a ChannelManager")]),t._v(" "),s("p",[t._v("The "),s("code",[t._v("ChannelManager")]),t._v(" is responsible for several tasks related to managing channel state. This includes keeping track of many channels, sending messages to appropriate channels, creating channels and more.")]),t._v(" "),s("h2",{attrs:{id:"adding-a-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#adding-a-channelmanager"}},[t._v("#")]),t._v(" Adding a ChannelManager")]),t._v(" "),s("p",[t._v("Adding a "),s("code",[t._v("ChannelManager")]),t._v(" to your application should look something like this:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("channelmanager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("entropy_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("node_signer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("signer_provider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n current_timestamp\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("batteries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ChannelManagerConstructor\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scoringParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n routerWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// optional")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructionParameters "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructionParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n entropySource"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asEntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n nodeSigner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asNodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" keysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n enableP2PGossip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" scorer\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[t._v("There are a few dependencies needed to get this working. Let's walk through setting up each one so we can plug them into our "),s("code",[t._v("ChannelManager")]),t._v(".")]),t._v(" "),s("h3",{attrs:{id:"initialize-the-feeestimator"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-feeestimator"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("FeeEstimator")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" estimating fees for on-chain transactions that LDK wants broadcasted.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Background")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch background feerate,")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Normal")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch normal feerate (~6 blocks)")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HighPriority")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fetch high priority feerate")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// You can add the code here for this case")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_estimator "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("object "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimatorInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_Background")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_Normal")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKConfirmationTarget_HighPriority")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// return default fee rate")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\nval feeEstimator"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getEstSatPer1000Weight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmationTarget"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("253")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" confirmationTarget "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7500")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" feeEstimator "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFeeEstimator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ol",[s("li",[t._v("Fees must be returned in: satoshis per 1000 weight units")]),t._v(" "),s("li",[t._v("Fees must be no smaller than 253 (equivalent to 1 satoshi/vbyte, rounded up)")]),t._v(" "),s("li",[t._v("To reduce network traffic, you may want to cache fee results rather than\nretrieving fresh ones every time")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("FeeEstimator")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/FeeEstimator.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("FeeEstimator")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-router"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-router"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("Router")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" Finds a Route for a payment between the given payer and a payee.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" router "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultRouter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_secure_random_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringFeeParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" networkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" NetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Regtest")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("P2PGossipSync")]),t._v(", "),s("code",[t._v("Logger")]),t._v(", "),s("code",[t._v("KeysManager")]),t._v(", "),s("code",[t._v("Scorer")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/router/trait.Router.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Router")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Router.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Router")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-logger"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-logger"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" LDK logging")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourLogger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Record")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" raw_log "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" log "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{} {:<5} [{}:{}] {}\\n"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OffsetDateTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now_utc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"%F %T"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_string")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("module_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("line"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n raw_log\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourLogger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LoggerInterface "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("record"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Record"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourLogger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("log")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("record"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Record")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Print and/or write the log to a file")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" logger "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyLogger")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" you'll likely want to write the logs to a file for debugging purposes.")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/util/logger/trait.Logger.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Logger")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Logger.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Logger")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-broadcasterinterface"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-broadcasterinterface"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("BroadcasterInterface")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" broadcasting various transactions to the bitcoin network")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourTxBroadcaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" broadcaster "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroadcaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourTxBroadcaster"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BroadcasterInterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("BroadcasterInterfaceInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_transactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("out")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" txBroadcaster"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BroadcasterInterface "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" BroadcasterInterface"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourTxBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroacaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BroadcasterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("broadcastTransactions")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to broadcast a list of transactions")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" broadcaster "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxBroacaster")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("BroadcasterInterface")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("BroadcasterInterface")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-persist"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-persist"}},[t._v("#")]),t._v(" Initialize "),s("code",[t._v("Persist")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" persisting "),s("code",[t._v("ChannelMonitor")]),t._v("s, which contain crucial channel data, in a timely manner")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Sign")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Persist")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourPersister")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("persist_new_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateErr")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note that monitor.encode() will get you the ChannelMonitor as a")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Vec.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_persisted_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n update"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelSigner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateErr")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" YourPersister"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Persist"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("PersistInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("persist_new_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" OutPoint"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("data")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MonitorUpdateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_NoneChannelMonitorUpdateErrZ"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_persisted_channel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n id"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" OutPoint"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" update"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitorUpdate"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("data")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ChannelMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n updateId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" MonitorUpdateId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_NoneChannelMonitorUpdateErrZ"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" persister"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Persist "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Persist"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("YourPersister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Persist")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("persistNewChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MonitorUpdateId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateStatus")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert the code to persist the ChannelMonitor to disk")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("updatePersistedChannel")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutPoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" update"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" updateId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MonitorUpdateId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelMonitorUpdateStatus")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert the code to persist either ChannelMonitor or ChannelMonitorUpdate to disk")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Using LDK Sample Filesystem Persistence Crate in Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FilesystemPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// import LDK sample persist crate")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" persister "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FilesystemPersister")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ldk_data_dir_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ul",[s("li",[s("code",[t._v("ChannelMonitor")]),t._v("s are objects which are capable of\nresponding to on-chain events for a given channel. Thus, you will have one\n"),s("code",[t._v("ChannelMonitor")]),t._v(" per channel. They are persisted in real-time and the "),s("code",[t._v("Persist")]),t._v("\nmethods will block progress on sending or receiving payments until they return.\nYou must ensure that "),s("code",[t._v("ChannelMonitor")]),t._v("s are durably persisted to disk before\nreturning or you may lose funds.")]),t._v(" "),s("li",[t._v("If you implement a custom persister, it's important to read the trait docs (linked in References) to make sure you satisfy the API requirements, particularly for "),s("code",[t._v("update_persisted_channel")])])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Persister")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Persist.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Persister")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"start-background-processing"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#start-background-processing"}},[t._v("#")]),t._v(" Start Background Processing")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" running tasks periodically in the background to keep LDK operational.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" background_processor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BackgroundProcessor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("start")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("invoice_payer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("net_graph_msg_handler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("peer_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("ChannelManager")]),t._v(", "),s("code",[t._v("ChainMonitor")]),t._v(", "),s("code",[t._v("PeerManager")]),t._v(", "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning-background-processor/*/lightning_background_processor/struct.BackgroundProcessor.html#method.start",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("BackgroundProcessor::Start")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"regularly-broadcast-node-announcement"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#regularly-broadcast-node-announcement"}},[t._v("#")]),t._v(" Regularly Broadcast Node Announcement")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if you have 1 or more public channels, you may need to announce your node and its channels occasionally. LDK will automatically announce channels when they are created, but there are no guarantees you have connected peers at that time or that your peers will propagate such announcements. The broader node-announcement message is not automatically broadcast.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" interval "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("tokio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Duration")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("loop")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tinterval"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tick")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\tchannel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("broadcast_node_announcement")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert your node's RGB color")]),t._v("\n\t\tnode_alias"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("vec!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("ldk_announced_listen_addr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("Peer Manager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html#method.broadcast_node_announcement",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("PeerManager::broadcast_node_announcement")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-the-transaction-filter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-the-transaction-filter"}},[t._v("#")]),t._v(" Optional: Initialize the Transaction "),s("code",[t._v("Filter")])]),t._v(" "),s("p",[s("strong",[t._v("You must follow this step if:")]),t._v(" you are "),s("em",[t._v("not")]),t._v(" providing full blocks to LDK,\ni.e. if you're using BIP 157/158 or Electrum as your chain backend")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if you are not providing full blocks, LDK uses this\nobject to tell you what transactions and outputs to watch for on-chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Txid")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("usize")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("object "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("FilterInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_tx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" script_pubkey"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n override fun "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("register_output")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\nval txFilter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourTxFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("registerTx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" scriptPubkey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to watch this transaction")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("registerOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("output"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WatchedOutput")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to watch for any transaction that spend this output")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyFilter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" see the "),s("RouterLink",{attrs:{to:"/blockchain_data/introduction/"}},[t._v("Blockchain Data")]),t._v(" guide for more info")],1),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("em",[t._v("none")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("Filter")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Filter.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("Filter")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-chainmonitor"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-chainmonitor"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("ChainMonitor")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" tracking one or more "),s("code",[t._v("ChannelMonitor")]),t._v("s and using them to monitor the chain for lighting transactions that are relevant to our node, and broadcasting transactions if need be.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Box")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as None or insert the Filter trait object")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chain_monitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val filter "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as `null` or insert the Filter object.")]),t._v("\n\nval chainMonitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// leave this as `nil` or insert the Filter object.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chainMonitor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainMonitor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n chainSource"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" persister\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" "),s("code",[t._v("Filter")]),t._v(" must be non-"),s("code",[t._v("None")]),t._v(" if you're using Electrum or BIP 157/158 as your chain backend")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("FeeEstimator")]),t._v(", "),s("code",[t._v("Logger")]),t._v(", "),s("code",[t._v("BroadcasterInterface")]),t._v(", "),s("code",[t._v("Persist")])]),t._v(" "),s("p",[s("strong",[t._v("Optional dependency:")]),t._v(" "),s("code",[t._v("Filter")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chainmonitor/struct.ChainMonitor.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ChainMonitor")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChainMonitor.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ChainMonitor")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-keysmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-keysmanager"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("KeysManager")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" providing keys for signing Lightning transactions")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_seed_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/keys_seed"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If we're restarting and already have a key seed, read it from disk. Else,")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// create a new one.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("fs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("assert_eq!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("len")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("copy_from_slice")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n key\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("thread_rng")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fill_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("File")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("create")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write_all")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to write node keys seed to disk"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n f"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sync_all")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to sync node keys seed to disk"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ERROR: Unable to create keys seed file {}: {}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keys_seed_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n key\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" cur "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val keySeed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nval keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n keySeed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to create seed with random bytes or if restarting, reload the seed from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("ul",[s("li",[t._v("See the "),s("RouterLink",{attrs:{to:"/key_management/"}},[t._v("Key Management")]),t._v(" guide for more info")],1),t._v(" "),s("li",[t._v("Note that you must write the "),s("code",[t._v("key_seed")]),t._v(" you give to the "),s("code",[t._v("KeysManager")]),t._v(" on\nstartup to disk, and keep using it to initialize the "),s("code",[t._v("KeysManager")]),t._v(" every time\nyou restart. This "),s("code",[t._v("key_seed")]),t._v(" is used to derive your node's secret key (which\ncorresponds to its node pubkey) and all other secret key material.")]),t._v(" "),s("li",[t._v("The current time is part of the "),s("code",[t._v("KeysManager")]),t._v("'s parameters because it is used to derive\nrandom numbers from the seed where required, to ensure all random\ngeneration is unique across restarts.")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" random bytes")]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("KeysManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/KeysManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("KeysManager")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"read-channelmonitor-state-from-disk"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#read-channelmonitor-state-from-disk"}},[t._v("#")]),t._v(" Read "),s("code",[t._v("ChannelMonitor")]),t._v(" state from disk")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" if LDK is restarting and has at least 1 channel, its "),s("code",[t._v("ChannelMonitor")]),t._v("s will need to be (1) fed to the "),s("code",[t._v("ChannelManager")]),t._v(" and (2) synced to chain.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's sample persister crate provided method")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_monitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_channelmonitors")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If you are using Electrum or BIP 157/158, you must call load_outputs_to_watch")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// on each ChannelMonitor to prepare for chain synchronization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" chan_mon "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chan_mon"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("load_outputs_to_watch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialize the hashmap where we'll store the `ChannelMonitor`s read from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This hashmap will later be given to the `ChannelManager` on initialization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" channelMonitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" arrayOf"),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nval channelMonitorList "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchannelMonitorFiles"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iterator")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forEach "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n val channelMonitorBytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" it"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("hexStringToByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n channelMonitorList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelMonitorBytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nchannelMonitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelMonitorList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTypedArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialize the array where we'll store the `ChannelMonitor`s read from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This array will later be given to the `ChannelManagerConstructor` on initialization.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" allChannels "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to get a list of persisted channels")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" channel "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" allChannels "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelData "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Data")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("contentsOf"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channel"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelBytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelBytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("KeysManager")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/channelmonitor/struct.ChannelMonitor.html#method.load_outputs_to_watch",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("load_outputs_to_watch")]),t._v(" docs"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"initialize-the-channelmanager"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialize-the-channelmanager"}},[t._v("#")]),t._v(" Initialize the "),s("code",[t._v("ChannelManager")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" managing channel state")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" user_config "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserConfig")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* RESTARTING */")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channel_manager_file "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("fs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("File")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("open")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/manager"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use the `ChannelMonitors` we read from disk.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_monitor_mut_references "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter_mut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channel_monitor_mut_references"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" read_args "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerReadArgs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channel_monitor_mut_references"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager_file"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" read_args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* FRESH CHANNELMANAGER */")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" best_blockhash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert the best blockhash you know of")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" best_chain_height "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert the height corresponding to best_blockhash")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" chain_params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChainParameters")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// substitute this with your network")]),t._v("\n best_block"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("best_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" best_chain_height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fresh_channel_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("chain_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("router"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("entropy_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("node_signer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("signer_provider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_config"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n current_timestamp\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("best_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fresh_channel_manager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("serializedChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isNotEmpty")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Loading from disk (restarting)")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txFilter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringFeeParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n scorer"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("write")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fresh start")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Regtest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userConfig"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_EntropySource")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_NodeSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_impl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("keysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feeEstimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n ProbabilisticScoringFeeParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n txBroadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" serializedChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("isEmpty "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelManagerSerialized"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelMonitorsSerialized"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedChannelMonitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraphArgument")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("instance")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" filter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" channelManagerConstructor "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelManagerConstructor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHash"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n currentBlockchainTipHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" latestBlockHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerConstructionParameters\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" No methods should be called on "),s("code",[t._v("ChannelManager")]),t._v(" until\n"),s("em",[t._v("after")]),t._v(" the "),s("code",[t._v("ChannelMonitor")]),t._v("s and "),s("code",[t._v("ChannelManager")]),t._v(" are synced to the chain tip (next step).")]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("KeysManager")]),t._v(", "),s("code",[t._v("FeeEstimator")]),t._v(", "),s("code",[t._v("ChainMonitor")]),t._v(", "),s("code",[t._v("BroadcasterInterface")]),t._v(", "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ChannelManager")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChannelManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ChannelManager")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"sync-channelmonitors-and-channelmanager-to-chain-tip"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#sync-channelmonitors-and-channelmanager-to-chain-tip"}},[t._v("#")]),t._v(" Sync "),s("code",[t._v("ChannelMonitor")]),t._v("s and "),s("code",[t._v("ChannelManager")]),t._v(" to chain tip")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" this step is only necessary if you're restarting and have open channels. This step ensures that LDK channel state is up-to-date with the bitcoin blockchain")]),t._v(" "),s("p",[s("strong",[t._v("Example:")])]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Full Blocks or BIP 157/158")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("init"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("poll"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UnboundedCache")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning_block_sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourChainBackend")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_header")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height_hint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHeaderData")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" header_hash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_best_block")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token lifetime-annotation symbol"}},[t._v("'a")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AsyncBlockSourceResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockHash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" block_source "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("YourChainBackend")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_listener_channel_monitors "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" cache "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UnboundedCache")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_tip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("poll"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ValidatedBlockHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" chain_listeners "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("vec!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_manager_blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" channel_manager "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Listen")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("drain")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" outpoint "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_funding_txo")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n chain_listener_channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n blockhash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channel_monitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("broadcaster"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("fee_estimator"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outpoint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" monitor_listener_info "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" chain_listener_channel_monitors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter_mut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chain_listeners"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n monitor_listener_info"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" monitor_listener_info"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Listen")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Save the chain tip to be used in future steps")]),t._v("\nchain_tip "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Some")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("init"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("synchronize_listeners")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" block_source"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" cache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n chain_listeners"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Electrum/Esplora")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transaction IDs to check the chain for un-confirmation.")]),t._v("\nval relevantTxIdsFromChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Confirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_relevant_txids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval relevantTxIdsFromChannelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Confirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_relevant_txids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval relevantTxIds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relevantTxIdsFromChannelManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" relevantTxIdsFromChainMonitor\n\nval unconfirmedTxs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid in unconfirmedTxs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transaction_unconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transaction_unconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transactions and outputs that were registered through the `Filter`")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// interface.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If any of these txs/outputs were confirmed on-chain, then:")]),t._v("\nval header"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert block header from the block with confirmed tx/output")]),t._v("\nval height"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert block height of `header`")]),t._v("\nval txIndex"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Long")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert tx index in block")]),t._v("\nval serializedTx"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// insert tx hex as byte array")]),t._v("\nval tx"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" serializedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Marshall all TwoTuples you built right above into an array")]),t._v("\nval txList "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" arrayOf"),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoTuple_usizeTransactionZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactions_confirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactions_confirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\nval bestHeader"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Array")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nval bestHeight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ")]),t._v("\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_best_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_best_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Finally, tell LDK that chain sync is complete. This will also spawn several")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// background threads to handle networking and event processing.")]),t._v("\nchannelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chain_sync_completed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("customEventHandler"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Electrum/Esplora")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transaction IDs to check the chain for un-confirmation.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" relevantTxIds1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRelevantTxids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" relevantTxIds2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" chainMonitor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRelevantTxids")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("??")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" relevantTxIds1 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" tx "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" relevantTxIds2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n relevantTxIds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" unconfirmedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to find out from your chain source")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// if any of relevantTxIds have been reorged out")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// of the chain")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" txid "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" unconfirmedTx "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionUnconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionUnconfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" txid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Retrieve transactions and outputs that were registered through the `Filter` interface.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" confirmedTx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to find out from your chain source")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// if any of the `Filter` txs/outputs were confirmed")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// on-chain")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" txid "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" confirmedTx "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch header")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch height of the header")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch tx")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch tx index")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("append")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("txIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n channelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionsConfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txdata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n chainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("transactionsConfirmed")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" txdata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" twoTuple"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bestHeader "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch best header")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bestHeight "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Insert code to fetch best height")]),t._v("\n\nchannelManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bestBlockUpdated")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nchainMonitor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asConfirm")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bestBlockUpdated")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" height"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bestHeight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Finally, tell LDK that chain sync is complete. This will also spawn several")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// background threads to handle networking and event processing.")]),t._v("\nchannelManagerConstructor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chainSyncCompleted")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("persister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelManagerPersister"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")])]),t._v(" "),s("p",[t._v("There are 2 main options for synchronizing to chain on startup:")]),t._v(" "),s("p",[s("strong",[t._v("Full Blocks or BIP 157/158")])]),t._v(" "),s("p",[t._v("If you are connecting full blocks or using BIP 157/158, then it is recommended to use\nLDK's "),s("code",[t._v("lightning_block_sync")]),t._v(" crate as in the example above: the high-level steps that must be done for both "),s("code",[t._v("ChannelManager")]),t._v(" and each "),s("code",[t._v("ChannelMonitor")]),t._v(" are as follows:")]),t._v(" "),s("ol",[s("li",[t._v("Get the last blockhash that each object saw.\n"),s("ul",[s("li",[t._v("Receive the latest block hash when through "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManagerReadArgs.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("deserializtion"),s("OutboundLink")],1),t._v(" of the "),s("code",[t._v("ChannelManager")]),t._v(" via "),s("code",[t._v("read()")])]),t._v(" "),s("li",[t._v("Each "),s("code",[t._v("ChannelMonitor")]),t._v("'s is in "),s("code",[t._v("channel_manager.channel_monitors")]),t._v(", as the 2nd element in each tuple")])])]),t._v(" "),s("li",[t._v("For each object, if its latest known blockhash has been reorged out of the chain, then disconnect blocks using "),s("code",[t._v("channel_manager.as_Listen().block_disconnected(..)")]),t._v(" or "),s("code",[t._v("channel_monitor.block_disconnected(..)")]),t._v(" until you reach the last common ancestor with the main chain.")]),t._v(" "),s("li",[t._v("For each object, reconnect blocks starting from the common ancestor until it gets to your best known chain tip using "),s("code",[t._v("channel_manager.as_Listen().block_connected(..)")]),t._v(" and/or "),s("code",[t._v("channel_monitor.block_connected(..)")]),t._v(".")]),t._v(" "),s("li",[t._v("Call "),s("code",[t._v("channel_manager.chain_sync_completed(..)")]),t._v(" to complete the initial sync process.")])]),t._v(" "),s("p",[s("strong",[t._v("Electrum/Esplora")])]),t._v(" "),s("p",[t._v("Alternatively, you can use LDK's "),s("code",[t._v("lightning-transaction-sync")]),t._v(" crate. This provides utilities for syncing LDK via the transaction-based "),s("code",[t._v("Confirm")]),t._v(" interface.")]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-p2pgossipsync-or-rapidgossipsync"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-p2pgossipsync-or-rapidgossipsync"}},[t._v("#")]),t._v(" Optional: Initialize "),s("code",[t._v("P2PGossipSync or RapidGossipSync")])]),t._v(" "),s("p",[s("strong",[t._v("You must follow this step if:")]),t._v(" you need LDK to provide routes for sending payments (i.e. you are "),s("em",[t._v("not")]),t._v(" providing your own routes)")]),t._v(" "),s("p",[s("strong",[t._v("What it's used for:")]),t._v(" generating routes to send payments over")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" genesis "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("genesis_block")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("header"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_hash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/network_graph"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" genesis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" gossip_sync "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("dyn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("chain"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Access")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Send")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Sync")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[t._v("val genesisBlock "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BestBlock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("from_genesis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("LDKNetwork_Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval genesisBlockHash "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("byteArrayToHex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("genesisBlock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("block_hash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nval serializedNetworkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read network graph bytes from file")]),t._v("\nval networkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("serializedNetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nval p2pGossip "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("P2PGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option_AccessZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("none")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Network Graph exists, then read from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedNetworkGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read Network Graph bytes from file")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" readResult "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ser"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedNetworkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" arg"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" readResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" readResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Network Graph does not exist, create a new one")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" netGraph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NetworkGraph")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Initialise RGS")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" rgs "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RapidGossipSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lastSync "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getLastRapidGossipSyncTimestamp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" snapshot "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" lastSync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("updateNetworkGraphNoStd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("updateData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" snapshot"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currentTimeUnix"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"RGS updated"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" snapshot "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use lastSyncTimeStamp as 0 for first Sync")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" rgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("updateNetworkGraphNoStd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("updateData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" snapshot"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currentTimeUnix"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"RGS initialized for the first time"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Get current snapshot from the RGS Server")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getSnapshot")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("lastSyncTimeStamp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use LDK's RGS Server or use your own Server")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("URL")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("URL")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("string"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://rapidsync.lightningdevkit.org/snapshot/')]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("\\(")]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[t._v("lastSyncTimeStamp")]),s("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use the url to get the data")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" data "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Implementation notes:")]),t._v(" this struct is not required if you are providing your own routes. It will be used internally in "),s("code",[t._v("ChannelManager")]),t._v(" to build a "),s("code",[t._v("NetworkGraph")]),t._v(". Network options include: "),s("code",[t._v("Mainnet")]),t._v(","),s("code",[t._v("Regtest")]),t._v(","),s("code",[t._v("Testnet")]),t._v(","),s("code",[t._v("Signet")])]),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("Logger")])]),t._v(" "),s("p",[s("strong",[t._v("Optional dependency:")]),t._v(" "),s("code",[t._v("Access")]),t._v(", a source of chain information. Recommended to be able to verify channels before adding them to the internal network graph.")]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/gossip/struct.P2PGossipSync.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("P2PGossipSync")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Access.html",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("Access")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/P2PGossipSync.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("P2PGossipSync")]),t._v(" bindings"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("RapidGossipSync")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RapidGossipSync.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("RapidGossipSync")]),t._v(" bindings"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"optional-initialize-probabilistic-scorer"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#optional-initialize-probabilistic-scorer"}},[t._v("#")]),t._v(" Optional: Initialize "),s("code",[t._v("Probabilistic Scorer")])]),t._v(" "),s("p",[s("strong",[t._v("What it's used for")]),t._v(": to find a suitable payment path to reach the destination.")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/network_graph"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" network_graph "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer_path "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("format!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"{}/scorer"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ldk_data_dir"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RwLock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("disk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_scorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Path")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("scorer_path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("network_graph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("clone")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("exists")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" scorerReaderResult "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerFile"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("readBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerReaderResult"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("is_ok"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("scorerReaderResult "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_ProbabilisticScorerDecodeErrorZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_ProbabilisticScorerDecodeErrorZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Probabilistic Scorer loaded and running"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Couldn\'t load Probabilistic Scorer"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Log"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("i")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("LDKTAG"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"LDK: Creating a new Probabilistic Scorer"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScoringDecayParameters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("with_default")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MultiThreadedLockableScore"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_Score")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-Swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Scorer exists, then read from disk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Read Scorer bytes from file")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringDecayParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" serializedProbabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n ser"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" serializedScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argA"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argB"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n argC"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" serializedProbabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" res\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" score "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Scorer loaded")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MultiThreadedLockableScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If Scorer does not exist, create a new one")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" decayParams "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScoringDecayParameters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithDefault")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" probabilisticScorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ProbabilisticScorer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" decayParams"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n networkGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" netGraph"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n logger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" logger\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" score "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" probabilisticScorer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Scorer loaded")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" scorer "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MultiThreadedLockableScore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" score"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("p",[s("strong",[t._v("Dependencies:")]),t._v(" "),s("code",[t._v("NetworkGraph")])]),t._v(" "),s("p",[s("strong",[t._v("References:")]),t._v(" "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/routing/scoring/struct.ProbabilisticScorer.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),s("code",[t._v("ProbabilisticScorer")]),t._v(" docs"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ProbabilisticScorer.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),s("code",[t._v("ProbabilisticScorer")]),t._v(" docs"),s("OutboundLink")],1)])],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/53.9c51f591.js b/assets/js/53.0033aefa.js similarity index 99% rename from assets/js/53.9c51f591.js rename to assets/js/53.0033aefa.js index 42ed077df..bc7235531 100644 --- a/assets/js/53.9c51f591.js +++ b/assets/js/53.0033aefa.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{420:function(t,a,s){"use strict";s.r(a);var n=s(7),e=Object(n.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"setting-up-a-peermanager"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-a-peermanager"}},[t._v("#")]),t._v(" Setting up a "),a("code",[t._v("PeerManager")])]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("PeerManager")]),t._v(" is responsible for managing a set of peer connections and data associated with those peers.")]),t._v(" "),a("h2",{attrs:{id:"adding-a-peermanager"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-a-peermanager"}},[t._v("#")]),t._v(" Adding a "),a("code",[t._v("PeerManager")])]),t._v(" "),a("p",[t._v("To add a "),a("code",[t._v("PeerManager")]),t._v(" to your application, run:")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("peer_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" ephemeral_bytes "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("rand"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("thread_rng")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fill_bytes")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" ephemeral_bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lightning_msg_handler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MessageHandler")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chan_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n route_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" gossip_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n onion_message_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onion_messenger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n custom_message_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IgnoringMessageHandler")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peer_manager "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n lightning_msg_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n cur_time"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("try_into")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("log_error!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to get current time: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BuildError")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvalidSystemTime")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("ephemeral_bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v("\n\nval peerManager"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peer_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peerManager\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("Implementation notes:")]),t._v(" if you did not initialize "),a("code",[t._v("P2PGossipSync")]),t._v(" in the previous step, you can initialize your own struct (which can be a dummy struct) that implements "),a("code",[t._v("RoutingMessageHandler")])]),t._v(" "),a("p",[a("strong",[t._v("Dependencies:")]),t._v(" "),a("code",[t._v("ChannelManager")]),t._v(", "),a("code",[t._v("RoutingMessageHandler")]),t._v(", "),a("code",[t._v("KeysManager")]),t._v(", random bytes, "),a("code",[t._v("Logger")])]),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PeerManager")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/msgs/trait.RoutingMessageHandler.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("RoutingMessageHandler")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PeerManager")]),t._v(" bindings"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RoutingMessageHandler.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("RoutingMessageHandler")]),t._v(" bindings"),a("OutboundLink")],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{418:function(t,a,s){"use strict";s.r(a);var n=s(7),e=Object(n.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"setting-up-a-peermanager"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-a-peermanager"}},[t._v("#")]),t._v(" Setting up a "),a("code",[t._v("PeerManager")])]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("PeerManager")]),t._v(" is responsible for managing a set of peer connections and data associated with those peers.")]),t._v(" "),a("h2",{attrs:{id:"adding-a-peermanager"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-a-peermanager"}},[t._v("#")]),t._v(" Adding a "),a("code",[t._v("PeerManager")])]),t._v(" "),a("p",[t._v("To add a "),a("code",[t._v("PeerManager")]),t._v(" to your application, run:")]),t._v(" "),a("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("ln"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("peer_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" ephemeral_bytes "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("rand"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("thread_rng")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fill_bytes")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" ephemeral_bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" lightning_msg_handler "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MessageHandler")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n chan_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channel_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n route_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" gossip_sync"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n onion_message_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onion_messenger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n custom_message_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IgnoringMessageHandler")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peer_manager "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n lightning_msg_handler"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n cur_time"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("try_into")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("log_error!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to get current time: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BuildError")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InvalidSystemTime")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("ephemeral_bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("logger"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("keys_manager\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldk"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("structs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v("\n\nval peerManager"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peer_manager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[a("div",{staticClass:"language-Swift extra-class"},[a("pre",{pre:!0,attrs:{class:"language-swift"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LightningDevKit")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" peerManager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PeerManager")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" channelManagerConstructor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("peerManager\n")])])])]},proxy:!0}])}),t._v(" "),a("p",[a("strong",[t._v("Implementation notes:")]),t._v(" if you did not initialize "),a("code",[t._v("P2PGossipSync")]),t._v(" in the previous step, you can initialize your own struct (which can be a dummy struct) that implements "),a("code",[t._v("RoutingMessageHandler")])]),t._v(" "),a("p",[a("strong",[t._v("Dependencies:")]),t._v(" "),a("code",[t._v("ChannelManager")]),t._v(", "),a("code",[t._v("RoutingMessageHandler")]),t._v(", "),a("code",[t._v("KeysManager")]),t._v(", random bytes, "),a("code",[t._v("Logger")])]),t._v(" "),a("p",[a("strong",[t._v("References:")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("PeerManager")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/ln/msgs/trait.RoutingMessageHandler.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust "),a("code",[t._v("RoutingMessageHandler")]),t._v(" docs"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("PeerManager")]),t._v(" bindings"),a("OutboundLink")],1),t._v(", "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RoutingMessageHandler.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java/Kotlin "),a("code",[t._v("RoutingMessageHandler")]),t._v(" bindings"),a("OutboundLink")],1)])],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/54.40e417d9.js b/assets/js/54.22f8d4b4.js similarity index 99% rename from assets/js/54.40e417d9.js rename to assets/js/54.22f8d4b4.js index 127b6f0d8..28db2c9b6 100644 --- a/assets/js/54.40e417d9.js +++ b/assets/js/54.22f8d4b4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[54],{423:function(e,t,i){"use strict";i.r(t);var o=i(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"ldk-code-of-conduct"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-code-of-conduct"}},[e._v("#")]),e._v(" LDK Code of Conduct")]),e._v(" "),t("p",[e._v("The LDK community is open to pretty much anyone. To ensure that project forums such as the Discord server and GitHub repository are open and friendly, we count on maintainers and project representatives to behave in a way that is not disruptive to LDK's culture or to any one participant's well-being.")]),e._v(" "),t("p",[e._v("Therefore, we came up with some easy to follow guidelines.")]),e._v(" "),t("ul",[t("li",[e._v("Be friendly. Interact in a way that fosters openness, inclusivity, and collaboration.")]),e._v(" "),t("li",[e._v("Be respectful. We may disagree, but disagreement is no excuse for rude behavior or personal attacks.")]),e._v(" "),t("li",[e._v("Be considerate. Provide and accept constructive criticism.")])]),e._v(" "),t("p",[e._v("Private or public harassment of any kind will not be tolerated. Since harassment can take many forms, here's a non-exhaustive list of what we consider unacceptable behavior:")]),e._v(" "),t("ul",[t("li",[e._v("Offensive language directed at individuals or groups of people")]),e._v(" "),t("li",[e._v("Bullying (verbal, physical, social, or cyber)")]),e._v(" "),t("li",[e._v("Interfering with someone's ability to contribute, like with excessive nitpicking")]),e._v(" "),t("li",[e._v("Continued one-on-one communication after a party has requested it cease")]),e._v(" "),t("li",[e._v("Stalking online or offline")]),e._v(" "),t("li",[e._v("Doxing or unauthorized publication of private information or communication")]),e._v(" "),t("li",[e._v("Unwelcomed sexual attention")]),e._v(" "),t("li",[e._v("Inappropriate visual displays such as sexually-oriented or offensive photography, cartoons, drawings, or gestures")]),e._v(" "),t("li",[e._v("Retaliation for reporting or threatening to report harassment")])]),e._v(" "),t("p",[e._v("Additionally, spam and other content which disrupts or prevents LDK contributors from working on LDK is not acceptable.")]),e._v(" "),t("h2",{attrs:{id:"the-code-of-conduct-team"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#the-code-of-conduct-team"}},[e._v("#")]),e._v(" The Code of Conduct Team")]),e._v(" "),t("p",[e._v("A small team of LDK contributors has volunteered to enforce the LDK Code of Conduct. If you feel like a community member has engaged in inappropriate behavior, please don't hesitate to contact one of the following LDK contributors via email or on Discord:")]),e._v(" "),t("ul",[t("li",[e._v("Matt Corallo - ldkcocpoc on mattcorallo.com")]),e._v(" "),t("li",[e._v("Val Wallace - vwallace on protonmail.com")]),e._v(" "),t("li",[e._v("Devrandom - devrandom99 on proton.me")])]),e._v(" "),t("h2",{attrs:{id:"the-code-of-conduct-team-s-responsibilities"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#the-code-of-conduct-team-s-responsibilities"}},[e._v("#")]),e._v(" The Code of Conduct Team’s Responsibilities")]),e._v(" "),t("p",[e._v("Team members are tasked with responding to reports within 24 hours. They will review each incident and determine, to the best of their ability:")]),e._v(" "),t("ul",[t("li",[e._v("Does the event constitute a Code of Conduct violation?")]),e._v(" "),t("li",[e._v("Is the behavior on our list of inappropriate behavior? Is it borderline inappropriate?")]),e._v(" "),t("li",[e._v("Did the event occur in a space within our Code of Conduct's scope?\n"),t("ul",[t("li",[e._v("If the incident occurred outside community forums and the individual is seen as a project representative or identifies as an LDK contributor, the incident may be in scope.")]),e._v(" "),t("li",[e._v("Additionally, an incident may be in scope if a community member's ability to contribute to LDK is impacted.")])])]),e._v(" "),t("li",[e._v("Did this incident occur in a private conversation or in a public space?")]),e._v(" "),t("li",[e._v("Is the situation isolated or ongoing?")]),e._v(" "),t("li",[e._v("How is the reported person's behavior negatively impacting others?")]),e._v(" "),t("li",[e._v("Does the incident impact the ability of individuals to freely contribute to LDK?")]),e._v(" "),t("li",[e._v("Does this incident include sexual harassment?")]),e._v(" "),t("li",[e._v("Does this pose a safety risk or severely negatively impact someone's mental health?")]),e._v(" "),t("li",[e._v("Is there a risk of this behavior being repeated?")]),e._v(" "),t("li",[e._v("Does the reported person understand why their behavior was inappropriate?")])]),e._v(" "),t("p",[e._v("If a report is insufficiently detailed or involves multiple parties, the Code of Conduct Team may seek additional information from witnesses or the accused. Neither party should contact the other to discuss the incident. Likewise, the team will do its best not to disclose who reported a given incident, either to the accused or generally, though we recognize that circumstantial disclosures to the accused might be unavoidable.")]),e._v(" "),t("p",[e._v("The Code of Conduct Team aims to resolve all reports within one week. If a resolution is not possible within that time frame, the team will respond to the reporter(s) with an adjusted one.")]),e._v(" "),t("h2",{attrs:{id:"possible-responses-to-an-incident-include"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#possible-responses-to-an-incident-include"}},[e._v("#")]),e._v(" Possible responses to an incident include:")]),e._v(" "),t("h3",{attrs:{id:"taking-no-further-action"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#taking-no-further-action"}},[e._v("#")]),e._v(" Taking no further action:")]),e._v(" "),t("p",[e._v("If the Code of Conduct Team determines that no action is needed, they will inform the reporter.")]),e._v(" "),t("h3",{attrs:{id:"simple-warning"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#simple-warning"}},[e._v("#")]),e._v(" Simple warning:")]),e._v(" "),t("p",[e._v("This applies to disruptive behavior, but not insulting behavior. The Code of Conduct Team will contact the individual(s) and request that they stop.")]),e._v(" "),t("h3",{attrs:{id:"final-warning"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#final-warning"}},[e._v("#")]),e._v(" Final warning:")]),e._v(" "),t("p",[e._v("If an incident or series of incidents creates sustained toxicity within the LDK Community, the Code of Conduct Team will sternly warn the reported party and raise the possibility of further disciplinary action. In addition, they may request that the reported party:")]),e._v(" "),t("ul",[t("li",[e._v("Not use specific language")]),e._v(" "),t("li",[e._v("Not participate in specific types of discussions")]),e._v(" "),t("li",[e._v("Not send private messages to a community member")]),e._v(" "),t("li",[e._v("Not review a particular person's PRs on GitHub (but still allow them to privately share review comments with a maintainer)")]),e._v(" "),t("li",[e._v("Not lead sub-projects like code review sessions")]),e._v(" "),t("li",[e._v("Take a step away for a short period to cool off")]),e._v(" "),t("li",[e._v("Lose maintainer/merge access")])]),e._v(" "),t("h3",{attrs:{id:"2-3-months-imposed-break"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#2-3-months-imposed-break"}},[e._v("#")]),e._v(" 2-3 months imposed break:")]),e._v(" "),t("p",[e._v("If the Code of Conduct Team’s warning goes unheeded, the individual(s) may be asked to avoid participating with the LDK Community on its preferred platforms for several months. After time has passed, the individual(s) will have the option of meeting with the team to discuss returning to the community.")]),e._v(" "),t("h3",{attrs:{id:"extended-or-permanent-ban"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#extended-or-permanent-ban"}},[e._v("#")]),e._v(" Extended or permanent ban:")]),e._v(" "),t("p",[e._v("If a temporary break does not remedy a serious offense, the offender may be removed from the Discord server and Github repository. The Code of Conduct Team may also choose to un-ban a user for a first offense, depending on its severity and pending that the user has offered the offended party a genuine apology.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[54],{420:function(e,t,i){"use strict";i.r(t);var o=i(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"ldk-code-of-conduct"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-code-of-conduct"}},[e._v("#")]),e._v(" LDK Code of Conduct")]),e._v(" "),t("p",[e._v("The LDK community is open to pretty much anyone. To ensure that project forums such as the Discord server and GitHub repository are open and friendly, we count on maintainers and project representatives to behave in a way that is not disruptive to LDK's culture or to any one participant's well-being.")]),e._v(" "),t("p",[e._v("Therefore, we came up with some easy to follow guidelines.")]),e._v(" "),t("ul",[t("li",[e._v("Be friendly. Interact in a way that fosters openness, inclusivity, and collaboration.")]),e._v(" "),t("li",[e._v("Be respectful. We may disagree, but disagreement is no excuse for rude behavior or personal attacks.")]),e._v(" "),t("li",[e._v("Be considerate. Provide and accept constructive criticism.")])]),e._v(" "),t("p",[e._v("Private or public harassment of any kind will not be tolerated. Since harassment can take many forms, here's a non-exhaustive list of what we consider unacceptable behavior:")]),e._v(" "),t("ul",[t("li",[e._v("Offensive language directed at individuals or groups of people")]),e._v(" "),t("li",[e._v("Bullying (verbal, physical, social, or cyber)")]),e._v(" "),t("li",[e._v("Interfering with someone's ability to contribute, like with excessive nitpicking")]),e._v(" "),t("li",[e._v("Continued one-on-one communication after a party has requested it cease")]),e._v(" "),t("li",[e._v("Stalking online or offline")]),e._v(" "),t("li",[e._v("Doxing or unauthorized publication of private information or communication")]),e._v(" "),t("li",[e._v("Unwelcomed sexual attention")]),e._v(" "),t("li",[e._v("Inappropriate visual displays such as sexually-oriented or offensive photography, cartoons, drawings, or gestures")]),e._v(" "),t("li",[e._v("Retaliation for reporting or threatening to report harassment")])]),e._v(" "),t("p",[e._v("Additionally, spam and other content which disrupts or prevents LDK contributors from working on LDK is not acceptable.")]),e._v(" "),t("h2",{attrs:{id:"the-code-of-conduct-team"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#the-code-of-conduct-team"}},[e._v("#")]),e._v(" The Code of Conduct Team")]),e._v(" "),t("p",[e._v("A small team of LDK contributors has volunteered to enforce the LDK Code of Conduct. If you feel like a community member has engaged in inappropriate behavior, please don't hesitate to contact one of the following LDK contributors via email or on Discord:")]),e._v(" "),t("ul",[t("li",[e._v("Matt Corallo - ldkcocpoc on mattcorallo.com")]),e._v(" "),t("li",[e._v("Val Wallace - vwallace on protonmail.com")]),e._v(" "),t("li",[e._v("Devrandom - devrandom99 on proton.me")])]),e._v(" "),t("h2",{attrs:{id:"the-code-of-conduct-team-s-responsibilities"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#the-code-of-conduct-team-s-responsibilities"}},[e._v("#")]),e._v(" The Code of Conduct Team’s Responsibilities")]),e._v(" "),t("p",[e._v("Team members are tasked with responding to reports within 24 hours. They will review each incident and determine, to the best of their ability:")]),e._v(" "),t("ul",[t("li",[e._v("Does the event constitute a Code of Conduct violation?")]),e._v(" "),t("li",[e._v("Is the behavior on our list of inappropriate behavior? Is it borderline inappropriate?")]),e._v(" "),t("li",[e._v("Did the event occur in a space within our Code of Conduct's scope?\n"),t("ul",[t("li",[e._v("If the incident occurred outside community forums and the individual is seen as a project representative or identifies as an LDK contributor, the incident may be in scope.")]),e._v(" "),t("li",[e._v("Additionally, an incident may be in scope if a community member's ability to contribute to LDK is impacted.")])])]),e._v(" "),t("li",[e._v("Did this incident occur in a private conversation or in a public space?")]),e._v(" "),t("li",[e._v("Is the situation isolated or ongoing?")]),e._v(" "),t("li",[e._v("How is the reported person's behavior negatively impacting others?")]),e._v(" "),t("li",[e._v("Does the incident impact the ability of individuals to freely contribute to LDK?")]),e._v(" "),t("li",[e._v("Does this incident include sexual harassment?")]),e._v(" "),t("li",[e._v("Does this pose a safety risk or severely negatively impact someone's mental health?")]),e._v(" "),t("li",[e._v("Is there a risk of this behavior being repeated?")]),e._v(" "),t("li",[e._v("Does the reported person understand why their behavior was inappropriate?")])]),e._v(" "),t("p",[e._v("If a report is insufficiently detailed or involves multiple parties, the Code of Conduct Team may seek additional information from witnesses or the accused. Neither party should contact the other to discuss the incident. Likewise, the team will do its best not to disclose who reported a given incident, either to the accused or generally, though we recognize that circumstantial disclosures to the accused might be unavoidable.")]),e._v(" "),t("p",[e._v("The Code of Conduct Team aims to resolve all reports within one week. If a resolution is not possible within that time frame, the team will respond to the reporter(s) with an adjusted one.")]),e._v(" "),t("h2",{attrs:{id:"possible-responses-to-an-incident-include"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#possible-responses-to-an-incident-include"}},[e._v("#")]),e._v(" Possible responses to an incident include:")]),e._v(" "),t("h3",{attrs:{id:"taking-no-further-action"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#taking-no-further-action"}},[e._v("#")]),e._v(" Taking no further action:")]),e._v(" "),t("p",[e._v("If the Code of Conduct Team determines that no action is needed, they will inform the reporter.")]),e._v(" "),t("h3",{attrs:{id:"simple-warning"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#simple-warning"}},[e._v("#")]),e._v(" Simple warning:")]),e._v(" "),t("p",[e._v("This applies to disruptive behavior, but not insulting behavior. The Code of Conduct Team will contact the individual(s) and request that they stop.")]),e._v(" "),t("h3",{attrs:{id:"final-warning"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#final-warning"}},[e._v("#")]),e._v(" Final warning:")]),e._v(" "),t("p",[e._v("If an incident or series of incidents creates sustained toxicity within the LDK Community, the Code of Conduct Team will sternly warn the reported party and raise the possibility of further disciplinary action. In addition, they may request that the reported party:")]),e._v(" "),t("ul",[t("li",[e._v("Not use specific language")]),e._v(" "),t("li",[e._v("Not participate in specific types of discussions")]),e._v(" "),t("li",[e._v("Not send private messages to a community member")]),e._v(" "),t("li",[e._v("Not review a particular person's PRs on GitHub (but still allow them to privately share review comments with a maintainer)")]),e._v(" "),t("li",[e._v("Not lead sub-projects like code review sessions")]),e._v(" "),t("li",[e._v("Take a step away for a short period to cool off")]),e._v(" "),t("li",[e._v("Lose maintainer/merge access")])]),e._v(" "),t("h3",{attrs:{id:"2-3-months-imposed-break"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#2-3-months-imposed-break"}},[e._v("#")]),e._v(" 2-3 months imposed break:")]),e._v(" "),t("p",[e._v("If the Code of Conduct Team’s warning goes unheeded, the individual(s) may be asked to avoid participating with the LDK Community on its preferred platforms for several months. After time has passed, the individual(s) will have the option of meeting with the team to discuss returning to the community.")]),e._v(" "),t("h3",{attrs:{id:"extended-or-permanent-ban"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#extended-or-permanent-ban"}},[e._v("#")]),e._v(" Extended or permanent ban:")]),e._v(" "),t("p",[e._v("If a temporary break does not remedy a serious offense, the offender may be removed from the Discord server and Github repository. The Code of Conduct Team may also choose to un-ban a user for a first offense, depending on its severity and pending that the user has offered the offended party a genuine apology.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/55.8d0ac9ac.js b/assets/js/55.1343484c.js similarity index 99% rename from assets/js/55.8d0ac9ac.js rename to assets/js/55.1343484c.js index 7aa1b9c6c..1e3d305ba 100644 --- a/assets/js/55.8d0ac9ac.js +++ b/assets/js/55.1343484c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[55],{422:function(e,t,a){"use strict";a.r(t);var r=a(7),n=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"examples"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[e._v("#")]),e._v(" Examples")]),e._v(" "),t("p",[e._v("Click the links below and learn from community-built example projects")]),e._v(" "),t("h3",{attrs:{id:"rust-sample-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-sample-node"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust Sample Node"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample serves as a complete reference for constructing a lightning node with\nLDK. This is a good starting point if you want a self-guided tour.")]),e._v(" "),t("h3",{attrs:{id:"kotlinandroid-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#kotlinandroid-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/conorokus/umlando-wallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kotlin/Android Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses the Kotlin bindings provided by "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-garbagecollected"),t("OutboundLink")],1),e._v(" to create a self-custodial mobile lightning wallet on Android.")]),e._v(" "),t("h3",{attrs:{id:"swiftios-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#swiftios-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/Roy0Anonymous/Vajra-Wallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Swift/iOS Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses the Swift bindings provided by "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-swift",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-swift"),t("OutboundLink")],1),e._v(" to create a self-custodial mobile lightning wallet on iOS.")]),e._v(" "),t("h3",{attrs:{id:"rust-node-with-sample-lightning-signer-integration"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-node-with-sample-lightning-signer-integration"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://gitlab.com/lightning-signer/lnrod/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust node with sample Lightning Signer integration"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A Rust lightning node implementation based on LDK and the Lightning Signer projects. Aims to be production ready at some point.")]),e._v(" "),t("h3",{attrs:{id:"rust-node-with-sample-tor-integration"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-node-with-sample-tor-integration"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust node with sample Tor integration"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A Rust lightning node sample implementation based on LDK with an embedded Tor daemon.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A ready-to-go Lightning node library built using LDK and "),t("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-rust-sample"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-rust-sample"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/optout21/ldk-node-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Rust Sample"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A sample lightning node command-line app built on top of LDK Node (similar to ldk-sample).")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-swift-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-swift-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/reez/Monday/tree/main/LDKNodeMonday",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Swift Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/blob/main/Package.swift",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-node-swift"),t("OutboundLink")],1),e._v(" bindings to quickly build a self custodial lightning mobile wallet on iOS. Watch the video tutorial "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=rcU3LU6iZCs",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-swift-sample-app-using-bitcoin-design-guide"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-swift-sample-app-using-bitcoin-design-guide"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/bdgwallet/dailywallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Swift Sample app using Bitcoin Design Guide"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a good starting point for building a sample iOS wallet with a strong focus on user experience.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-flutter-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-flutter-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-flutter-demo",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Flutter Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a starting point for an LDK Node Flutter app.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-react-native-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-react-native-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-rn-demo",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node React Native Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a starting point for an LDK Node React Native app.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-sample-desktop-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-sample-desktop-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/jbesraa/ldk-node-desktop",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Sample Desktop App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a desktop node manager for LDK Node.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[55],{421:function(e,t,a){"use strict";a.r(t);var r=a(7),n=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"examples"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[e._v("#")]),e._v(" Examples")]),e._v(" "),t("p",[e._v("Click the links below and learn from community-built example projects")]),e._v(" "),t("h3",{attrs:{id:"rust-sample-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-sample-node"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust Sample Node"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample serves as a complete reference for constructing a lightning node with\nLDK. This is a good starting point if you want a self-guided tour.")]),e._v(" "),t("h3",{attrs:{id:"kotlinandroid-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#kotlinandroid-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/conorokus/umlando-wallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kotlin/Android Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses the Kotlin bindings provided by "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-garbagecollected",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-garbagecollected"),t("OutboundLink")],1),e._v(" to create a self-custodial mobile lightning wallet on Android.")]),e._v(" "),t("h3",{attrs:{id:"swiftios-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#swiftios-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/Roy0Anonymous/Vajra-Wallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("Swift/iOS Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses the Swift bindings provided by "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-swift",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-swift"),t("OutboundLink")],1),e._v(" to create a self-custodial mobile lightning wallet on iOS.")]),e._v(" "),t("h3",{attrs:{id:"rust-node-with-sample-lightning-signer-integration"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-node-with-sample-lightning-signer-integration"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://gitlab.com/lightning-signer/lnrod/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust node with sample Lightning Signer integration"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A Rust lightning node implementation based on LDK and the Lightning Signer projects. Aims to be production ready at some point.")]),e._v(" "),t("h3",{attrs:{id:"rust-node-with-sample-tor-integration"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rust-node-with-sample-tor-integration"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank",rel:"noopener noreferrer"}},[e._v("Rust node with sample Tor integration"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A Rust lightning node sample implementation based on LDK with an embedded Tor daemon.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A ready-to-go Lightning node library built using LDK and "),t("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("BDK"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-rust-sample"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-rust-sample"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/optout21/ldk-node-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Rust Sample"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("A sample lightning node command-line app built on top of LDK Node (similar to ldk-sample).")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-swift-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-swift-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/reez/Monday/tree/main/LDKNodeMonday",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Swift Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample uses "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/blob/main/Package.swift",target:"_blank",rel:"noopener noreferrer"}},[e._v("ldk-node-swift"),t("OutboundLink")],1),e._v(" bindings to quickly build a self custodial lightning mobile wallet on iOS. Watch the video tutorial "),t("a",{attrs:{href:"https://www.youtube.com/watch?v=rcU3LU6iZCs",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-swift-sample-app-using-bitcoin-design-guide"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-swift-sample-app-using-bitcoin-design-guide"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/bdgwallet/dailywallet",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Swift Sample app using Bitcoin Design Guide"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a good starting point for building a sample iOS wallet with a strong focus on user experience.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-flutter-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-flutter-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-flutter-demo",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Flutter Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a starting point for an LDK Node Flutter app.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-react-native-sample-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-react-native-sample-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/LtbLightning/ldk-node-rn-demo",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node React Native Sample App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a starting point for an LDK Node React Native app.")]),e._v(" "),t("h3",{attrs:{id:"ldk-node-sample-desktop-app"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ldk-node-sample-desktop-app"}},[e._v("#")]),e._v(" "),t("a",{attrs:{href:"https://github.com/jbesraa/ldk-node-desktop",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK Node Sample Desktop App"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("This sample is a desktop node manager for LDK Node.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/56.23f179fc.js b/assets/js/56.9d1ff47d.js similarity index 99% rename from assets/js/56.23f179fc.js rename to assets/js/56.9d1ff47d.js index b978b83e9..5fe659d9e 100644 --- a/assets/js/56.23f179fc.js +++ b/assets/js/56.9d1ff47d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[56],{424:function(t,a,e){"use strict";e.r(a);var s=e(7),n=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"fee-estimation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fee-estimation"}},[t._v("#")]),t._v(" Fee Estimation")]),t._v(" "),a("h2",{attrs:{id:"overview"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#overview"}},[t._v("#")]),t._v(" Overview")]),t._v(" "),a("p",[t._v("LDK provides a "),a("code",[t._v("FeeEstimator")]),t._v(" trait which, once implemented, assists in variety of on-chain and off-chain tasks. It's important to note that the "),a("code",[t._v("FeeEstimator")]),t._v(" only describes the architectural requirements that must be satisfied to successfully incorporate LDK into your project. It does not, itself, provide the logic or implementation to calculate a feerate.")]),t._v(" "),a("p",[t._v("In LDK, feerates are separated into seven categories. Each category is known as a "),a("code",[t._v("ConfirmationTarget")]),t._v(". We'll provide a brief review of these shortly, but, for now, it's sufficient to understand that these categories represent various scenarios in which we need feerate information. For example, one "),a("code",[t._v("ConfirmationTarget")]),t._v(" is "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(", which describes the lowest feerate we will allow our channel counterparty to have in an anchor channel.")]),t._v(" "),a("p",[t._v("Feerates and their functionality within LDK can be conceptually separated into on-chain (Bitcoin) and off-chain (Lightning Network) tasks.")]),t._v(" "),a("h4",{attrs:{id:"on-chain"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#on-chain"}},[t._v("#")]),t._v(" On-Chain")]),t._v(" "),a("p",[t._v("Lightning's security model is dependent on the ability to confirm a claim transaction under a variety of circumstances, such as before a timelock expires. To ensure that LDK is able to confirm claim transactions in a timely manner or bump the fee on an existing transaction, LDK utilizes the "),a("code",[t._v("FeeEstimator")]),t._v(" to fetch feerates for high priority transactions. For example, the "),a("code",[t._v("ConfirmationTarget::OnChainSweep")]),t._v(" specifies the feerate used when we have funds available on-chain that must be spent before a certain expiry time, beyond which our counterparty could potentially steal them. Additionally, the "),a("code",[t._v("ConfirmationTarget::OutputSpendingFee")]),t._v(" is used by the "),a("code",[t._v("OutputSweeper")]),t._v(" utility to ensure that, after channel closure, all funds are eventually swept to an onchain address controlled by the user.")]),t._v(" "),a("h4",{attrs:{id:"off-chain"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#off-chain"}},[t._v("#")]),t._v(" Off-Chain")]),t._v(" "),a("p",[t._v("From an off-chain perspective, the "),a("code",[t._v("FeeEstimator")]),t._v(" provides vital information that is used when opening, closing, and operating channels with peers on the Lightning Network. For example, when opening an inbound channel or updating an existing channel with a counterparty, LDK will compare the counterparty's proposed feerate with the minimum feerate that is allowed for that type of channel (ex: anchor or non-anchor channel). If the proposed fee is too low, LDK may return an error and suggest closing the channel. During these operations, LDK will reference the "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(" and the "),a("code",[t._v("ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee")]),t._v(". Therefore, it's recommended to ensure that the minimum allowable fees are not set too high, thus increasing the risk that a peer's proposed feerate is too low, potentially resulting in a force closure. See the "),a("a",{attrs:{href:"#best-practices"}},[a("strong",[t._v("Best Practices")])]),t._v(" section in this documentation for more helpful tips when implementing LDK's "),a("code",[t._v("FeeEstimator")]),t._v(".")]),t._v(" "),a("p",[t._v("Another instance where LDK utilizes the "),a("code",[t._v("FeeEstimator")]),t._v(" is during a cooperative channel closure. In this case, LDK references the "),a("code",[t._v("ConfirmationTarget::ChannelCloseMinimum")]),t._v(" and "),a("code",[t._v("ConfirmationTarget::NonAnchorChannelFee")]),t._v(" to estimate a feerate range, which is then proposed to the counterparty for closing the channel.")]),t._v(" "),a("h2",{attrs:{id:"the-feeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-feeestimator"}},[t._v("#")]),t._v(" The "),a("code",[t._v("FeeEstimator")])]),t._v(" "),a("p",[t._v("LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" trait (seen below) is at the heart of fee estimation within LDK.")]),t._v(" "),a("p",[t._v("You'll notice that it has "),a("strong",[t._v("one required method")]),t._v(", "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(". This method is referenced throughout LDK to fetch feerate information when performing actions such as opening lightning channels, closing lightning channels, or sweeping funds on-chain. You'll also notice that the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" has "),a("strong",[t._v("one required input")]),t._v(": a "),a("code",[t._v("ConfirmationTarget")]),t._v(". The next section will describe the "),a("code",[t._v("ConfirmationTarget")]),t._v(" in more detail. For now, it's important to note that the implementation of "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" must be completed by the developer. Once completed, this method should return the estimated fee (in sats/KW) for the given "),a("code",[t._v("ConfirmationTarget")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("trait")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// Gets estimated satoshis of fee required per 1000 Weight-Units.")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("///")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// LDK will wrap this method and ensure that the value returned is no smaller than 253")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("///")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// The following unit conversions can be used to convert to sats/KW:")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// * satoshis-per-byte * 250")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// * satoshis-per-kbyte / 4")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h2",{attrs:{id:"the-confirmationtarget"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-confirmationtarget"}},[t._v("#")]),t._v(" The "),a("code",[t._v("ConfirmationTarget")])]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("ConfirmationTarget")]),t._v(" enables the user to define the feerate that LDK will use for a variety of on-chain and off-chain tasks. For a detailed description of each "),a("code",[t._v("ConfirmationTarget")]),t._v(", please visit "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/enum.ConfirmationTarget.html#",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h2",{attrs:{id:"best-practices"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#best-practices"}},[t._v("#")]),t._v(" Best Practices")]),t._v(" "),a("h3",{attrs:{id:"estimating-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#estimating-fees"}},[t._v("#")]),t._v(" Estimating Fees")]),t._v(" "),a("p",[t._v("The end goal is to implement the function "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" such that it will return a feerate in sats/KW (satoshis-per-byte * 250) for each of the "),a("code",[t._v("ConfirmationTarget")]),t._v(" options. Therefore, the question is: "),a("strong",[t._v("how should we determine the right feerate to provide when "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" is called?")])]),t._v(" "),a("p",[t._v("A popular approach is to fetch feerate information from a third-party such as mempool.space by sending a GET request to their "),a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("get-recommended-fees"),a("OutboundLink")],1),t._v(" endpoint. Another option is to connect to your own local mempool. Depending on which approach you take, you may get fee estimates that are already separated into categories (ex: high, medium, low), or you may have to request fee estimates with a specific confirmation target in mind (ex: fetching fees for a transaction that you want to be mined within the next 6 blocks). Regardless of your approach, you will ultimately have to map the feerate estimate back to each "),a("code",[t._v("ConfirmationTarget")]),t._v(". To help make this easier, a table has been provided below with recommendations for how you could map each "),a("code",[t._v("ConfirmationTarget")]),t._v(" to both a mempool.space fee category and the estimated number of blocks each "),a("code",[t._v("ConfirmationTarget")]),t._v(" may represent. Please keep in mind, these are only recommendations. In practice, confirmation targets are influenced by each developer's fee strategy and risk-tolerance and may change accordingly.")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[t._v("ConfirmationTarget")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("mempool.space Category")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("Number of Blocks")])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("OnChainSweep")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("hour_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("6")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("minimum_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("1008")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("144")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("AnchorChannelFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("minimum_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("1008")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("12")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("144")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("OutputSpendingFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("12")])])])]),t._v(" "),a("p",[a("strong",[t._v("NOTE")]),t._v(": Setting "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(" or "),a("code",[t._v("ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("strong",[t._v("too high")]),t._v(", will increase the risk that a peer's proposed feerate is, comparatively, too low, potentially resulting in a force closure. Similarly, setting "),a("code",[t._v("ConfirmationTarget::AnchorChannelFee")]),t._v(" or "),a("code",[t._v("ConfirmationTarget::NonAnchorChannelFee")]),t._v(" "),a("strong",[t._v("too low")]),t._v(", will increase the risk that your node's proposed feerate is, comparatively, too low, potentially resulting in a force closure.")]),t._v(" "),a("h3",{attrs:{id:"general-architecture-approaches"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#general-architecture-approaches"}},[t._v("#")]),t._v(" General Architecture Approaches")]),t._v(" "),a("p",[t._v("Now that we've seen a few approaches towards retrieving feerate estimates such that we can return a recommended fee for each "),a("code",[t._v("ConfirmationTarget")]),t._v(", let's review some best practices for "),a("code",[t._v("FeeEstimator")]),t._v(" architecture.")]),t._v(" "),a("p",[t._v("First, let's circle back to "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" function. While there are many ways to develop logic to determine which feerate to provide for a specific "),a("code",[t._v("ConfirmationTarget")]),t._v(", a popular approach is to fetch this information using a tiered methodology. This will help ensure that, if there is a failure in retrieving fees from one method, another method can serve as a backup and ensure that normal node operations are not impacted. For example, one approach to populating fees is the following:")]),t._v(" "),a("ul",[a("li",[t._v("If mempool.space successfully returns fee estimates, use those.")]),t._v(" "),a("li",[t._v("Otherwise, fetch fee estimates from your local mempool")]),t._v(" "),a("li",[t._v("If both of the above fail, use hard-coded fall-back fees, mapped to each "),a("code",[t._v("ConfirmationTarget")]),t._v(".")])]),t._v(" "),a("p",[t._v("Please note, if you're using a third-party fee estimator, there are a few things you should keep in mind:")]),t._v(" "),a("ul",[a("li",[t._v("Third parties often rate-limit users such that they can only access a limited number of fee estimates within a given timeframe. If you require a certain service level agreement (SLA), it's recommended to run your own Bitcoin node or explore paid services with SLA guarantees, such as "),a("a",{attrs:{href:"https://mempool.space/enterprise",target:"_blank",rel:"noopener noreferrer"}},[t._v("mempool.space enterprise accounts"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("li",[t._v("Leveraging third-party providers may leave you more exposed to a griefing attack, where your fee estimator purposely overestimates the feerate, causing you to accept more dust HTLCs than you would otherwise.")]),t._v(" "),a("li",[t._v("Third-party fee estimates may affect the propagation of your pre-signed transactions at any time and, therefore, endanger the safety of channel funds.")])]),t._v(" "),a("p",[t._v("Running your own Bitcoin node can relieve some of these concerns, but it may require additional technical expertise and maintenance to operate properly. These trade-offs should be considered carefully when deciding how your application will retrieve fee estimates.")]),t._v(" "),a("p",[t._v("A savvy reader may have noticed that the above architecture is not very performant. LDK may generate a substantial number of fee-estimation calls in some cases. So, if we have to call an API every time we want a fee estimate, we'll add a significant amount of additional load to our application, and we may substantially slow HTLC handling. To ensure your application remains performant, you should pre-calculate and cache the fee estimates so that they can simply be retrieved when needed. Additionally, it's recommended to refresh fee estimates every 5-10 minutes so that your application has access to fresh freerates.")]),t._v(" "),a("h3",{attrs:{id:"feerate-api-options"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#feerate-api-options"}},[t._v("#")]),t._v(" Feerate API Options")]),t._v(" "),a("p",[t._v("While mempool.space serves as the primary example in this documentation, it is not the only third-party option for retrieving feerate estimates. A few more options are listed below. For completeness, mempool.space is also included below.")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[t._v("Third Party")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("API Documentation")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("Response Type")])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("Mempool.space")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Categories (ex: fastestFee, halfHourFee, hourFee, economyFee, minimumFee)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("Blockstream")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://github.com/Blockstream/esplora/blob/master/API.md#get-fee-estimates",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in blocks)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("bitcoiner.live")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://bitcoiner.live/doc/api",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in minutes)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("BitGo")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://developers.bitgo.com/api/v2.tx.getfeeestimate",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in blocks)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("blockchain.info")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Missing Documentation. API is here: https://api.blockchain.info/mempool/fees")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Categories (ex: regular, priority)")])])])]),t._v(" "),a("h2",{attrs:{id:"coding-example"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#coding-example"}},[t._v("#")]),t._v(" Coding Example")]),t._v(" "),a("p",[t._v("Now that we've reviewed the basic architecture, let's code up an example to demonstrate how you can implement the "),a("code",[t._v("FeeEstimator")]),t._v(" in your project.")]),t._v(" "),a("h3",{attrs:{id:"optional-set-up"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#optional-set-up"}},[t._v("#")]),t._v(" Optional: Set Up")]),t._v(" "),a("p",[t._v("If you'd like to follow along with this demo, you can set up a new Rust project using "),a("code",[t._v("cargo new")]),t._v(" followed by the name of the project. We'll call this "),a("code",[t._v("ldk-fee-estimator")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("$ cargo new ldk-fee-estimator\n$ cd ldk-fee-estimator\n")])])]),a("p",[t._v("Once you've created the directory, open the "),a("code",[t._v("Cargo.toml")]),t._v(" file, which Cargo uses to manage version and package dependencies, and copy/paste the following code into that file.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("package"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nname "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ldk-fee-estimator"')]),t._v("\nversion "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.1.0"')]),t._v("\nedition "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2021"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("dependencies"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nlightning "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"max_level_trace"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("block"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rpc-client"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.31.0"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("net"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("tokio "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("persister "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("background"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("processor "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("rapid"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("gossip"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nreqwest "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.11"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"json"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"blocking"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nserde "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"1.0"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"derive"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\ntokio "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"full"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" # "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Async")]),t._v(" runtime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" required "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" reqwest\n")])])]),a("p",[t._v("Finally, go to main.rs and place the following code at the top of the file.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("serde"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Deserialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("collections"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h3",{attrs:{id:"defining-myappfeeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#defining-myappfeeestimator"}},[t._v("#")]),t._v(" Defining "),a("code",[t._v("MyAppFeeEstimator")])]),t._v(" "),a("p",[t._v("First, we'll start by defining a structure, called "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", which will be used to store feerates associated with each "),a("code",[t._v("ConfirmationTarget")]),t._v(". The field "),a("code",[t._v("fee_rate_cache")]),t._v(" will contain a "),a("strong",[t._v("HashMap")]),t._v(" where the keys are of type "),a("code",[t._v("ConfirmationTarget")]),t._v(" and the values are the feerates (type "),a("code",[t._v("u32")]),t._v(") in sats/KW. We'll store them in sats/KW because, as we saw earlier, the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" method in LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/trait.FeeEstimator.html#required-methods",target:"_blank",rel:"noopener noreferrer"}},[t._v("expects fees to be provided in 1000 Weight-Units"),a("OutboundLink")],1),t._v(", so we'll store them in sats/KW.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-fees-from-mempoolspace-and-implementing-myappfeeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-fees-from-mempoolspace-and-implementing-myappfeeestimator"}},[t._v("#")]),t._v(" Retrieving Fees From mempool.space And Implementing "),a("code",[t._v("MyAppFeeEstimator")])]),t._v(" "),a("p",[t._v("Now that we have our basic structure for "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", let's write some code to fetch the feerates themselves. For this example, we'll fetch feerates from mempool.space. To do this, we'll start by defining a "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure. Since mempool's "),a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("recommmended fees API"),a("OutboundLink")],1),t._v(" returns five different feerates (fastestFee, halfHourFee, hourFee, economyFee, minimumFee), we'll create a field for each rate. Also, since this structure will have to deserialize \"camalCase\" JSON data fetched from the API, we'll have to add those attributes to our structure.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[derive(Deserialize, Debug)]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[serde(rename_all = "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"camelCase"')]),t._v(")]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MempoolFeeRate")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" fastest_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" half_hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" economy_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" minimum_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Now that our "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure is defined, we can begin building out the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(". We'll start by implementing the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" and adding our first function to this structure: "),a("code",[t._v("fetch_fee_from_mempool")]),t._v(". This function will fetch the feerates from mempool's API, process the response according to our "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure, and return the result. Since we'll be making an HTTP request using Rust's "),a("code",[t._v("reqwest")]),t._v(" crate, we'll tag this function as asynchronous ("),a("code",[t._v("async")]),t._v(").")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://mempool.space/api/v1/fees/recommended"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("json")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-default-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-default-fees"}},[t._v("#")]),t._v(" Retrieving Default Fees")]),t._v(" "),a("p",[t._v("Great, we now have a function that will return mempool.space feerates! However, as discussed earlier, we don't want to rely on only one source for our fee estimates. In a real production environment, we'd likely have a local mempool that we're sourcing feerates from and, perhaps, one or more third-party services. For this demo, we'll hard-code fallback feerates and return those if we're unable to retrieve a feerate from mepool.space.")]),t._v(" "),a("p",[t._v("Another reason we need default fee estimates is so that we can create instances of "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" without waiting for the feerates to be fetched from mempool.space (or any async operation). Therefore, we'll write a function that will return a hard-coded feerate for a given "),a("code",[t._v("ConfirmationTarget")]),t._v(". For simplicity, feerates below are presented as sats/vByte * 250 so that they are easier to read but, ultimately, they are stored within the cache as sats/KW. Note that this function is also a method within "),a("code",[t._v("MyAppFeeEstimator")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"creating-a-myappfeeestimator-instance"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-myappfeeestimator-instance"}},[t._v("#")]),t._v(" Creating a "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" Instance")]),t._v(" "),a("p",[t._v("Now that we've built the functionality to fetch feerates, we can start linking everything together. Let's begin by writing a "),a("code",[t._v("new")]),t._v(" method, which we'll call each time we initialize a fee estimator. The "),a("code",[t._v("new")]),t._v(" method will initialize an empty HashMap called "),a("code",[t._v("fee_rate_cache")]),t._v(", which we defined in our "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" structure earlier. It will then proceed to populate each of the required "),a("code",[t._v("ConfirmationTarget")]),t._v(" fields with its respective feerate. Remember, to ensure our application is performant and does not have to wait for network operations when initializing a fee estimator, we will originally load the feerates with our default values.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_rate_cache "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" target "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" default_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" default_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"updating-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-fees"}},[t._v("#")]),t._v(" Updating Fees")]),t._v(" "),a("p",[t._v("Great, we now have a "),a("code",[t._v("new")]),t._v(" function that will populate each instance of our fee estimator with the default rates.")]),t._v(" "),a("p",[t._v("However, we're not done yet! We already wrote code to fetch feerates from mempool.space, but we haven't inserted them into our cache. Let's do that now. We'll accomplish this by writing an "),a("code",[t._v("update_fees")]),t._v(" method. A keen eye will likely notice that the feerates are multiplied by 250 before being added to the cache. This is because mempool.space returns feerates in sats/vByte, but we need them in sats/KW, so we can multiply them by 250 to convert them to sats/KW and then store them within our cache. Make sure both "),a("code",[t._v("update_fees")]),t._v(" and "),a("code",[t._v("new")]),t._v(" are added as methods within "),a("code",[t._v("MyAppFeeEstimator")]),t._v("!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("economy_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If the API call fails, the fallback fees are already in cache")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-fees-based-on-a-confirmationtarget"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-fees-based-on-a-confirmationtarget"}},[t._v("#")]),t._v(" Retrieving Fees Based On A "),a("code",[t._v("ConfirmationTarget")])]),t._v(" "),a("p",[t._v("We're making solid progress! Remember, the end goal here is to build out a robust fee estimation logic that we can link back to the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" function in LDK's "),a("code",[t._v("FeeEstimator")]),t._v(". Since "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" takes one input, a "),a("code",[t._v("ConfirmationTarget")]),t._v(", we'll have to write a function that returns the feerate for a specific "),a("code",[t._v("ConfirmationTarget")]),t._v(". Now that we have mempool.space fees cached within the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", we can do just that. Also, to ensure that fee estimates are not too low such that they run the risk of never being mined, we'll check that the fee we return is at least 253 sats/KW. This fee is also enforced within LDK's implementation of the "),a("code",[t._v("FeeEstimator")]),t._v(" and is defined "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/constant.FEERATE_FLOOR_SATS_PER_KW.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(". We'll import this constant and use it in our function as well.")]),t._v(" "),a("p",[t._v("Below is a function that takes a "),a("code",[t._v("ConfirmationTarget")]),t._v(" as an input, fetches the feerate for that "),a("code",[t._v("ConfirmationTarget")]),t._v(" from our cache, and returns the result. If the fetched feerate is lower than the minimum feerate defined in LDK, "),a("code",[t._v("FEERATE_FLOOR_SATS_PER_KW")]),t._v(", we'll return "),a("code",[t._v("FEERATE_FLOOR_SATS_PER_KW")]),t._v(" instead. As with the above, make sure this is added as a method within "),a("code",[t._v("MyAppFeeEstimator")]),t._v("!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("max")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"all ConfirmationTarget should be present in the cache"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"linking-our-code-to-ldks-feeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linking-our-code-to-ldks-feeestimator"}},[t._v("#")]),t._v(" Linking Our Code To LDK's "),a("code",[t._v("FeeEstimator")])]),t._v(" "),a("p",[t._v("Finally, we'll link our code to LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" by specifying that the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" is a concrete implementation of the "),a("code",[t._v("FeeEstimator")]),t._v(" and we have satisfied the trait requirement that "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" is implemented.")]),t._v(" "),a("p",[t._v("Since we've already done most of the work, all we have to do is call the "),a("code",[t._v("get_fee_rate")]),t._v(" in our "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", and it will retrieve the feerate for the specified "),a("code",[t._v("ConfirmationTarget")]),t._v(", returning the value in sats/KW (satoshis-per-byte * 250), as specified by the LDK documentation.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"testing-and-improving-our-code"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing-and-improving-our-code"}},[t._v("#")]),t._v(" Testing And Improving Our Code")]),t._v(" "),a("p",[t._v("Now that the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" has been completed, we can create an instance of the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" and run a few tests.")]),t._v(" "),a("p",[t._v("In the below code, we start by creating "),a("code",[t._v("fee_estimator")]),t._v(", an instance of the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(". Remember, since the "),a("code",[t._v("fee_estimator")]),t._v(" is originally initialized with default values, we'll have to call "),a("code",[t._v("update_fees()")]),t._v(" to fetch feerates from mempool.space and insert those updates into our cache.")]),t._v(" "),a("p",[t._v("We then define two fee targets, "),a("code",[t._v("high_fee_target")]),t._v(" and "),a("code",[t._v("low_fee_target")]),t._v(" for the "),a("code",[t._v("ConfirmationTarget::OnChainSweep")]),t._v(" and "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(". Finally, we'll pass these confirmation targets into "),a("code",[t._v("fee_estimator.get_est_sat_per_1000_weight")]),t._v(" and print the feerates (sats/KW) to the terminal.")]),t._v(" "),a("p",[t._v("One best-practice that was not implemented in this demo but is left as an exercise to the developer is refreshing the updates every 5-10 minutes. One approach toward accomplishing that would be to keep track of the last time the "),a("code",[t._v("fee_estimator")]),t._v(" fees were refreshed and create a background process to update those fees periodically. Another exercise that is left to the reader is to create additional functionality within the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" to retrieve the feerate for custom circumstances. For example, you could create a function called "),a("code",[t._v("get_high_feerate")]),t._v(", which takes no arguments and, instead, returns the feerate that should be used for a high-priority transaction. If you'd like to review a production-quality implementation of a "),a("code",[t._v("FeeEstimator")]),t._v(", you can review LDK Node's implementation "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/blob/main/src/fee_estimator.rs",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[tokio::main]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_estimator "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to update fees: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example of calling 'get_est_sat_per_1000_weight' with a specific confirmation target")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" high_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" low_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"demo-codebase"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#demo-codebase"}},[t._v("#")]),t._v(" Demo Codebase")]),t._v(" "),a("p",[t._v("If you've been following the demo or would like to run/experiment with this code yourself, the entire main.rs file is provided below.")]),t._v(" "),a("p",[t._v("Just run "),a("code",[t._v("$ cargo run")]),t._v(" in the terminal (from the root directory of this project), and you'll see live fee estimates print to your terminal!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("serde"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Deserialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("collections"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[derive(Deserialize, Debug)]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[serde(rename_all = "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"camelCase"')]),t._v(")]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MempoolFeeRate")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" fastest_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" half_hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" economy_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" minimum_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://mempool.space/api/v1/fees/recommended"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("json")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_rate_cache "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" target "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" default_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" default_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("economy_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If the API call fails, the fallback fees are alreadyy in cache")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("max")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"all ConfirmationTarget should be present in the cache"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[tokio::main]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_estimator "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to update fees: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example of calling 'get_est_sat_per_1000_weight' with a specific confirmation target")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" high_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" low_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[56],{422:function(t,a,e){"use strict";e.r(a);var s=e(7),n=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"fee-estimation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fee-estimation"}},[t._v("#")]),t._v(" Fee Estimation")]),t._v(" "),a("h2",{attrs:{id:"overview"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#overview"}},[t._v("#")]),t._v(" Overview")]),t._v(" "),a("p",[t._v("LDK provides a "),a("code",[t._v("FeeEstimator")]),t._v(" trait which, once implemented, assists in variety of on-chain and off-chain tasks. It's important to note that the "),a("code",[t._v("FeeEstimator")]),t._v(" only describes the architectural requirements that must be satisfied to successfully incorporate LDK into your project. It does not, itself, provide the logic or implementation to calculate a feerate.")]),t._v(" "),a("p",[t._v("In LDK, feerates are separated into seven categories. Each category is known as a "),a("code",[t._v("ConfirmationTarget")]),t._v(". We'll provide a brief review of these shortly, but, for now, it's sufficient to understand that these categories represent various scenarios in which we need feerate information. For example, one "),a("code",[t._v("ConfirmationTarget")]),t._v(" is "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(", which describes the lowest feerate we will allow our channel counterparty to have in an anchor channel.")]),t._v(" "),a("p",[t._v("Feerates and their functionality within LDK can be conceptually separated into on-chain (Bitcoin) and off-chain (Lightning Network) tasks.")]),t._v(" "),a("h4",{attrs:{id:"on-chain"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#on-chain"}},[t._v("#")]),t._v(" On-Chain")]),t._v(" "),a("p",[t._v("Lightning's security model is dependent on the ability to confirm a claim transaction under a variety of circumstances, such as before a timelock expires. To ensure that LDK is able to confirm claim transactions in a timely manner or bump the fee on an existing transaction, LDK utilizes the "),a("code",[t._v("FeeEstimator")]),t._v(" to fetch feerates for high priority transactions. For example, the "),a("code",[t._v("ConfirmationTarget::OnChainSweep")]),t._v(" specifies the feerate used when we have funds available on-chain that must be spent before a certain expiry time, beyond which our counterparty could potentially steal them. Additionally, the "),a("code",[t._v("ConfirmationTarget::OutputSpendingFee")]),t._v(" is used by the "),a("code",[t._v("OutputSweeper")]),t._v(" utility to ensure that, after channel closure, all funds are eventually swept to an onchain address controlled by the user.")]),t._v(" "),a("h4",{attrs:{id:"off-chain"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#off-chain"}},[t._v("#")]),t._v(" Off-Chain")]),t._v(" "),a("p",[t._v("From an off-chain perspective, the "),a("code",[t._v("FeeEstimator")]),t._v(" provides vital information that is used when opening, closing, and operating channels with peers on the Lightning Network. For example, when opening an inbound channel or updating an existing channel with a counterparty, LDK will compare the counterparty's proposed feerate with the minimum feerate that is allowed for that type of channel (ex: anchor or non-anchor channel). If the proposed fee is too low, LDK may return an error and suggest closing the channel. During these operations, LDK will reference the "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(" and the "),a("code",[t._v("ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee")]),t._v(". Therefore, it's recommended to ensure that the minimum allowable fees are not set too high, thus increasing the risk that a peer's proposed feerate is too low, potentially resulting in a force closure. See the "),a("a",{attrs:{href:"#best-practices"}},[a("strong",[t._v("Best Practices")])]),t._v(" section in this documentation for more helpful tips when implementing LDK's "),a("code",[t._v("FeeEstimator")]),t._v(".")]),t._v(" "),a("p",[t._v("Another instance where LDK utilizes the "),a("code",[t._v("FeeEstimator")]),t._v(" is during a cooperative channel closure. In this case, LDK references the "),a("code",[t._v("ConfirmationTarget::ChannelCloseMinimum")]),t._v(" and "),a("code",[t._v("ConfirmationTarget::NonAnchorChannelFee")]),t._v(" to estimate a feerate range, which is then proposed to the counterparty for closing the channel.")]),t._v(" "),a("h2",{attrs:{id:"the-feeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-feeestimator"}},[t._v("#")]),t._v(" The "),a("code",[t._v("FeeEstimator")])]),t._v(" "),a("p",[t._v("LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" trait (seen below) is at the heart of fee estimation within LDK.")]),t._v(" "),a("p",[t._v("You'll notice that it has "),a("strong",[t._v("one required method")]),t._v(", "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(". This method is referenced throughout LDK to fetch feerate information when performing actions such as opening lightning channels, closing lightning channels, or sweeping funds on-chain. You'll also notice that the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" has "),a("strong",[t._v("one required input")]),t._v(": a "),a("code",[t._v("ConfirmationTarget")]),t._v(". The next section will describe the "),a("code",[t._v("ConfirmationTarget")]),t._v(" in more detail. For now, it's important to note that the implementation of "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" must be completed by the developer. Once completed, this method should return the estimated fee (in sats/KW) for the given "),a("code",[t._v("ConfirmationTarget")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("trait")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// Gets estimated satoshis of fee required per 1000 Weight-Units.")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("///")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// LDK will wrap this method and ensure that the value returned is no smaller than 253")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// (ie 1 satoshi-per-byte rounded up to ensure later round-downs don't put us below 1 satoshi-per-byte).")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("///")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// The following unit conversions can be used to convert to sats/KW:")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// * satoshis-per-byte * 250")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/// * satoshis-per-kbyte / 4")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h2",{attrs:{id:"the-confirmationtarget"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#the-confirmationtarget"}},[t._v("#")]),t._v(" The "),a("code",[t._v("ConfirmationTarget")])]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("ConfirmationTarget")]),t._v(" enables the user to define the feerate that LDK will use for a variety of on-chain and off-chain tasks. For a detailed description of each "),a("code",[t._v("ConfirmationTarget")]),t._v(", please visit "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/enum.ConfirmationTarget.html#",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("h2",{attrs:{id:"best-practices"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#best-practices"}},[t._v("#")]),t._v(" Best Practices")]),t._v(" "),a("h3",{attrs:{id:"estimating-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#estimating-fees"}},[t._v("#")]),t._v(" Estimating Fees")]),t._v(" "),a("p",[t._v("The end goal is to implement the function "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" such that it will return a feerate in sats/KW (satoshis-per-byte * 250) for each of the "),a("code",[t._v("ConfirmationTarget")]),t._v(" options. Therefore, the question is: "),a("strong",[t._v("how should we determine the right feerate to provide when "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" is called?")])]),t._v(" "),a("p",[t._v("A popular approach is to fetch feerate information from a third-party such as mempool.space by sending a GET request to their "),a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("get-recommended-fees"),a("OutboundLink")],1),t._v(" endpoint. Another option is to connect to your own local mempool. Depending on which approach you take, you may get fee estimates that are already separated into categories (ex: high, medium, low), or you may have to request fee estimates with a specific confirmation target in mind (ex: fetching fees for a transaction that you want to be mined within the next 6 blocks). Regardless of your approach, you will ultimately have to map the feerate estimate back to each "),a("code",[t._v("ConfirmationTarget")]),t._v(". To help make this easier, a table has been provided below with recommendations for how you could map each "),a("code",[t._v("ConfirmationTarget")]),t._v(" to both a mempool.space fee category and the estimated number of blocks each "),a("code",[t._v("ConfirmationTarget")]),t._v(" may represent. Please keep in mind, these are only recommendations. In practice, confirmation targets are influenced by each developer's fee strategy and risk-tolerance and may change accordingly.")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[t._v("ConfirmationTarget")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("mempool.space Category")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("Number of Blocks")])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("OnChainSweep")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("hour_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("6")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("minimum_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("1008")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("144")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("AnchorChannelFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("minimum_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("1008")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("12")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("144")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("OutputSpendingFee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("economy_fee")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("12")])])])]),t._v(" "),a("p",[a("strong",[t._v("NOTE")]),t._v(": Setting "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(" or "),a("code",[t._v("ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("strong",[t._v("too high")]),t._v(", will increase the risk that a peer's proposed feerate is, comparatively, too low, potentially resulting in a force closure. Similarly, setting "),a("code",[t._v("ConfirmationTarget::AnchorChannelFee")]),t._v(" or "),a("code",[t._v("ConfirmationTarget::NonAnchorChannelFee")]),t._v(" "),a("strong",[t._v("too low")]),t._v(", will increase the risk that your node's proposed feerate is, comparatively, too low, potentially resulting in a force closure.")]),t._v(" "),a("h3",{attrs:{id:"general-architecture-approaches"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#general-architecture-approaches"}},[t._v("#")]),t._v(" General Architecture Approaches")]),t._v(" "),a("p",[t._v("Now that we've seen a few approaches towards retrieving feerate estimates such that we can return a recommended fee for each "),a("code",[t._v("ConfirmationTarget")]),t._v(", let's review some best practices for "),a("code",[t._v("FeeEstimator")]),t._v(" architecture.")]),t._v(" "),a("p",[t._v("First, let's circle back to "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" function. While there are many ways to develop logic to determine which feerate to provide for a specific "),a("code",[t._v("ConfirmationTarget")]),t._v(", a popular approach is to fetch this information using a tiered methodology. This will help ensure that, if there is a failure in retrieving fees from one method, another method can serve as a backup and ensure that normal node operations are not impacted. For example, one approach to populating fees is the following:")]),t._v(" "),a("ul",[a("li",[t._v("If mempool.space successfully returns fee estimates, use those.")]),t._v(" "),a("li",[t._v("Otherwise, fetch fee estimates from your local mempool")]),t._v(" "),a("li",[t._v("If both of the above fail, use hard-coded fall-back fees, mapped to each "),a("code",[t._v("ConfirmationTarget")]),t._v(".")])]),t._v(" "),a("p",[t._v("Please note, if you're using a third-party fee estimator, there are a few things you should keep in mind:")]),t._v(" "),a("ul",[a("li",[t._v("Third parties often rate-limit users such that they can only access a limited number of fee estimates within a given timeframe. If you require a certain service level agreement (SLA), it's recommended to run your own Bitcoin node or explore paid services with SLA guarantees, such as "),a("a",{attrs:{href:"https://mempool.space/enterprise",target:"_blank",rel:"noopener noreferrer"}},[t._v("mempool.space enterprise accounts"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("li",[t._v("Leveraging third-party providers may leave you more exposed to a griefing attack, where your fee estimator purposely overestimates the feerate, causing you to accept more dust HTLCs than you would otherwise.")]),t._v(" "),a("li",[t._v("Third-party fee estimates may affect the propagation of your pre-signed transactions at any time and, therefore, endanger the safety of channel funds.")])]),t._v(" "),a("p",[t._v("Running your own Bitcoin node can relieve some of these concerns, but it may require additional technical expertise and maintenance to operate properly. These trade-offs should be considered carefully when deciding how your application will retrieve fee estimates.")]),t._v(" "),a("p",[t._v("A savvy reader may have noticed that the above architecture is not very performant. LDK may generate a substantial number of fee-estimation calls in some cases. So, if we have to call an API every time we want a fee estimate, we'll add a significant amount of additional load to our application, and we may substantially slow HTLC handling. To ensure your application remains performant, you should pre-calculate and cache the fee estimates so that they can simply be retrieved when needed. Additionally, it's recommended to refresh fee estimates every 5-10 minutes so that your application has access to fresh freerates.")]),t._v(" "),a("h3",{attrs:{id:"feerate-api-options"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#feerate-api-options"}},[t._v("#")]),t._v(" Feerate API Options")]),t._v(" "),a("p",[t._v("While mempool.space serves as the primary example in this documentation, it is not the only third-party option for retrieving feerate estimates. A few more options are listed below. For completeness, mempool.space is also included below.")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[t._v("Third Party")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("API Documentation")]),t._v(" "),a("th",{staticStyle:{"text-align":"center"}},[t._v("Response Type")])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("Mempool.space")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Categories (ex: fastestFee, halfHourFee, hourFee, economyFee, minimumFee)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("Blockstream")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://github.com/Blockstream/esplora/blob/master/API.md#get-fee-estimates",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in blocks)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("bitcoiner.live")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://bitcoiner.live/doc/api",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in minutes)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("BitGo")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[a("a",{attrs:{href:"https://developers.bitgo.com/api/v2.tx.getfeeestimate",target:"_blank",rel:"noopener noreferrer"}},[t._v("API Docs"),a("OutboundLink")],1)]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Confirmation Targets (in blocks)")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("blockchain.info")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Missing Documentation. API is here: https://api.blockchain.info/mempool/fees")]),t._v(" "),a("td",{staticStyle:{"text-align":"center"}},[t._v("Categories (ex: regular, priority)")])])])]),t._v(" "),a("h2",{attrs:{id:"coding-example"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#coding-example"}},[t._v("#")]),t._v(" Coding Example")]),t._v(" "),a("p",[t._v("Now that we've reviewed the basic architecture, let's code up an example to demonstrate how you can implement the "),a("code",[t._v("FeeEstimator")]),t._v(" in your project.")]),t._v(" "),a("h3",{attrs:{id:"optional-set-up"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#optional-set-up"}},[t._v("#")]),t._v(" Optional: Set Up")]),t._v(" "),a("p",[t._v("If you'd like to follow along with this demo, you can set up a new Rust project using "),a("code",[t._v("cargo new")]),t._v(" followed by the name of the project. We'll call this "),a("code",[t._v("ldk-fee-estimator")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("$ cargo new ldk-fee-estimator\n$ cd ldk-fee-estimator\n")])])]),a("p",[t._v("Once you've created the directory, open the "),a("code",[t._v("Cargo.toml")]),t._v(" file, which Cargo uses to manage version and package dependencies, and copy/paste the following code into that file.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("package"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nname "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ldk-fee-estimator"')]),t._v("\nversion "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.1.0"')]),t._v("\nedition "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2021"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("dependencies"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nlightning "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"max_level_trace"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("block"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rpc-client"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("invoice "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.31.0"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("net"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("tokio "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("persister "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("background"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("processor "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nlightning"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("rapid"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("gossip"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("sync "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.123"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nreqwest "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.11"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"json"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"blocking"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\nserde "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"1.0"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"derive"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\ntokio "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" features "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"full"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" # "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Async")]),t._v(" runtime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" required "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" reqwest\n")])])]),a("p",[t._v("Finally, go to main.rs and place the following code at the top of the file.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("serde"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Deserialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("collections"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h3",{attrs:{id:"defining-myappfeeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#defining-myappfeeestimator"}},[t._v("#")]),t._v(" Defining "),a("code",[t._v("MyAppFeeEstimator")])]),t._v(" "),a("p",[t._v("First, we'll start by defining a structure, called "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", which will be used to store feerates associated with each "),a("code",[t._v("ConfirmationTarget")]),t._v(". The field "),a("code",[t._v("fee_rate_cache")]),t._v(" will contain a "),a("strong",[t._v("HashMap")]),t._v(" where the keys are of type "),a("code",[t._v("ConfirmationTarget")]),t._v(" and the values are the feerates (type "),a("code",[t._v("u32")]),t._v(") in sats/KW. We'll store them in sats/KW because, as we saw earlier, the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" method in LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/trait.FeeEstimator.html#required-methods",target:"_blank",rel:"noopener noreferrer"}},[t._v("expects fees to be provided in 1000 Weight-Units"),a("OutboundLink")],1),t._v(", so we'll store them in sats/KW.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-fees-from-mempoolspace-and-implementing-myappfeeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-fees-from-mempoolspace-and-implementing-myappfeeestimator"}},[t._v("#")]),t._v(" Retrieving Fees From mempool.space And Implementing "),a("code",[t._v("MyAppFeeEstimator")])]),t._v(" "),a("p",[t._v("Now that we have our basic structure for "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", let's write some code to fetch the feerates themselves. For this example, we'll fetch feerates from mempool.space. To do this, we'll start by defining a "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure. Since mempool's "),a("a",{attrs:{href:"https://mempool.space/docs/api/rest#get-recommended-fees",target:"_blank",rel:"noopener noreferrer"}},[t._v("recommmended fees API"),a("OutboundLink")],1),t._v(" returns five different feerates (fastestFee, halfHourFee, hourFee, economyFee, minimumFee), we'll create a field for each rate. Also, since this structure will have to deserialize \"camalCase\" JSON data fetched from the API, we'll have to add those attributes to our structure.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[derive(Deserialize, Debug)]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[serde(rename_all = "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"camelCase"')]),t._v(")]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MempoolFeeRate")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" fastest_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" half_hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" economy_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" minimum_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Now that our "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure is defined, we can begin building out the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(". We'll start by implementing the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" and adding our first function to this structure: "),a("code",[t._v("fetch_fee_from_mempool")]),t._v(". This function will fetch the feerates from mempool's API, process the response according to our "),a("code",[t._v("MempoolFeeRate")]),t._v(" structure, and return the result. Since we'll be making an HTTP request using Rust's "),a("code",[t._v("reqwest")]),t._v(" crate, we'll tag this function as asynchronous ("),a("code",[t._v("async")]),t._v(").")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://mempool.space/api/v1/fees/recommended"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("json")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-default-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-default-fees"}},[t._v("#")]),t._v(" Retrieving Default Fees")]),t._v(" "),a("p",[t._v("Great, we now have a function that will return mempool.space feerates! However, as discussed earlier, we don't want to rely on only one source for our fee estimates. In a real production environment, we'd likely have a local mempool that we're sourcing feerates from and, perhaps, one or more third-party services. For this demo, we'll hard-code fallback feerates and return those if we're unable to retrieve a feerate from mepool.space.")]),t._v(" "),a("p",[t._v("Another reason we need default fee estimates is so that we can create instances of "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" without waiting for the feerates to be fetched from mempool.space (or any async operation). Therefore, we'll write a function that will return a hard-coded feerate for a given "),a("code",[t._v("ConfirmationTarget")]),t._v(". For simplicity, feerates below are presented as sats/vByte * 250 so that they are easier to read but, ultimately, they are stored within the cache as sats/KW. Note that this function is also a method within "),a("code",[t._v("MyAppFeeEstimator")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"creating-a-myappfeeestimator-instance"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-myappfeeestimator-instance"}},[t._v("#")]),t._v(" Creating a "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" Instance")]),t._v(" "),a("p",[t._v("Now that we've built the functionality to fetch feerates, we can start linking everything together. Let's begin by writing a "),a("code",[t._v("new")]),t._v(" method, which we'll call each time we initialize a fee estimator. The "),a("code",[t._v("new")]),t._v(" method will initialize an empty HashMap called "),a("code",[t._v("fee_rate_cache")]),t._v(", which we defined in our "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" structure earlier. It will then proceed to populate each of the required "),a("code",[t._v("ConfirmationTarget")]),t._v(" fields with its respective feerate. Remember, to ensure our application is performant and does not have to wait for network operations when initializing a fee estimator, we will originally load the feerates with our default values.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_rate_cache "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" target "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" default_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" default_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"updating-fees"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-fees"}},[t._v("#")]),t._v(" Updating Fees")]),t._v(" "),a("p",[t._v("Great, we now have a "),a("code",[t._v("new")]),t._v(" function that will populate each instance of our fee estimator with the default rates.")]),t._v(" "),a("p",[t._v("However, we're not done yet! We already wrote code to fetch feerates from mempool.space, but we haven't inserted them into our cache. Let's do that now. We'll accomplish this by writing an "),a("code",[t._v("update_fees")]),t._v(" method. A keen eye will likely notice that the feerates are multiplied by 250 before being added to the cache. This is because mempool.space returns feerates in sats/vByte, but we need them in sats/KW, so we can multiply them by 250 to convert them to sats/KW and then store them within our cache. Make sure both "),a("code",[t._v("update_fees")]),t._v(" and "),a("code",[t._v("new")]),t._v(" are added as methods within "),a("code",[t._v("MyAppFeeEstimator")]),t._v("!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("economy_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If the API call fails, the fallback fees are already in cache")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"retrieving-fees-based-on-a-confirmationtarget"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#retrieving-fees-based-on-a-confirmationtarget"}},[t._v("#")]),t._v(" Retrieving Fees Based On A "),a("code",[t._v("ConfirmationTarget")])]),t._v(" "),a("p",[t._v("We're making solid progress! Remember, the end goal here is to build out a robust fee estimation logic that we can link back to the "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" function in LDK's "),a("code",[t._v("FeeEstimator")]),t._v(". Since "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" takes one input, a "),a("code",[t._v("ConfirmationTarget")]),t._v(", we'll have to write a function that returns the feerate for a specific "),a("code",[t._v("ConfirmationTarget")]),t._v(". Now that we have mempool.space fees cached within the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", we can do just that. Also, to ensure that fee estimates are not too low such that they run the risk of never being mined, we'll check that the fee we return is at least 253 sats/KW. This fee is also enforced within LDK's implementation of the "),a("code",[t._v("FeeEstimator")]),t._v(" and is defined "),a("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chaininterface/constant.FEERATE_FLOOR_SATS_PER_KW.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(". We'll import this constant and use it in our function as well.")]),t._v(" "),a("p",[t._v("Below is a function that takes a "),a("code",[t._v("ConfirmationTarget")]),t._v(" as an input, fetches the feerate for that "),a("code",[t._v("ConfirmationTarget")]),t._v(" from our cache, and returns the result. If the fetched feerate is lower than the minimum feerate defined in LDK, "),a("code",[t._v("FEERATE_FLOOR_SATS_PER_KW")]),t._v(", we'll return "),a("code",[t._v("FEERATE_FLOOR_SATS_PER_KW")]),t._v(" instead. As with the above, make sure this is added as a method within "),a("code",[t._v("MyAppFeeEstimator")]),t._v("!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("max")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"all ConfirmationTarget should be present in the cache"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"linking-our-code-to-ldks-feeestimator"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linking-our-code-to-ldks-feeestimator"}},[t._v("#")]),t._v(" Linking Our Code To LDK's "),a("code",[t._v("FeeEstimator")])]),t._v(" "),a("p",[t._v("Finally, we'll link our code to LDK's "),a("code",[t._v("FeeEstimator")]),t._v(" by specifying that the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" is a concrete implementation of the "),a("code",[t._v("FeeEstimator")]),t._v(" and we have satisfied the trait requirement that "),a("code",[t._v("get_est_sat_per_1000_weight")]),t._v(" is implemented.")]),t._v(" "),a("p",[t._v("Since we've already done most of the work, all we have to do is call the "),a("code",[t._v("get_fee_rate")]),t._v(" in our "),a("code",[t._v("MyAppFeeEstimator")]),t._v(", and it will retrieve the feerate for the specified "),a("code",[t._v("ConfirmationTarget")]),t._v(", returning the value in sats/KW (satoshis-per-byte * 250), as specified by the LDK documentation.")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"testing-and-improving-our-code"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#testing-and-improving-our-code"}},[t._v("#")]),t._v(" Testing And Improving Our Code")]),t._v(" "),a("p",[t._v("Now that the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" has been completed, we can create an instance of the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" and run a few tests.")]),t._v(" "),a("p",[t._v("In the below code, we start by creating "),a("code",[t._v("fee_estimator")]),t._v(", an instance of the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(". Remember, since the "),a("code",[t._v("fee_estimator")]),t._v(" is originally initialized with default values, we'll have to call "),a("code",[t._v("update_fees()")]),t._v(" to fetch feerates from mempool.space and insert those updates into our cache.")]),t._v(" "),a("p",[t._v("We then define two fee targets, "),a("code",[t._v("high_fee_target")]),t._v(" and "),a("code",[t._v("low_fee_target")]),t._v(" for the "),a("code",[t._v("ConfirmationTarget::OnChainSweep")]),t._v(" and "),a("code",[t._v("ConfirmationTarget::MinAllowedAnchorChannelRemoteFee")]),t._v(". Finally, we'll pass these confirmation targets into "),a("code",[t._v("fee_estimator.get_est_sat_per_1000_weight")]),t._v(" and print the feerates (sats/KW) to the terminal.")]),t._v(" "),a("p",[t._v("One best-practice that was not implemented in this demo but is left as an exercise to the developer is refreshing the updates every 5-10 minutes. One approach toward accomplishing that would be to keep track of the last time the "),a("code",[t._v("fee_estimator")]),t._v(" fees were refreshed and create a background process to update those fees periodically. Another exercise that is left to the reader is to create additional functionality within the "),a("code",[t._v("MyAppFeeEstimator")]),t._v(" to retrieve the feerate for custom circumstances. For example, you could create a function called "),a("code",[t._v("get_high_feerate")]),t._v(", which takes no arguments and, instead, returns the feerate that should be used for a high-priority transaction. If you'd like to review a production-quality implementation of a "),a("code",[t._v("FeeEstimator")]),t._v(", you can review LDK Node's implementation "),a("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-node/blob/main/src/fee_estimator.rs",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[tokio::main]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_estimator "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to update fees: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example of calling 'get_est_sat_per_1000_weight' with a specific confirmation target")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" high_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" low_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"demo-codebase"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#demo-codebase"}},[t._v("#")]),t._v(" Demo Codebase")]),t._v(" "),a("p",[t._v("If you've been following the demo or would like to run/experiment with this code yourself, the entire main.rs file is provided below.")]),t._v(" "),a("p",[t._v("Just run "),a("code",[t._v("$ cargo run")]),t._v(" in the terminal (from the root directory of this project), and you'll see live fee estimates print to your terminal!")]),t._v(" "),a("div",{staticClass:"language-rust extra-class"},[a("pre",{pre:!0,attrs:{class:"language-rust"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("chaininterface"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("serde"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Deserialize")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("collections"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("std"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[derive(Deserialize, Debug)]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[serde(rename_all = "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"camelCase"')]),t._v(")]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("MempoolFeeRate")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" fastest_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" half_hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" hour_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" economy_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" minimum_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" url "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://mempool.space/api/v1/fees/recommended"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Client")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("json")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MempoolFeeRate")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_rate_cache "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashMap")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("use")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" target "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" default_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" default_fee"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n fee_rate_cache\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("reqwest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("fetch_fee_from_mempool")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" fee_rates "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fastest_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("economy_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insert")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rates"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("minimum_fee "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// If the API call fails, the fallback fees are alreadyy in cache")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fee_rate_cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("map")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token closure-params"}},[a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("cmp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("max")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("rate"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FEERATE_FLOOR_SATS_PER_KW")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("expect")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"all ConfirmationTarget should be present in the cache"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("default_fee_from_conf_target")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" confirmation_target "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedNonAnchorChannelRemoteFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChannelCloseMinimum")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NonAnchorChannelFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OutputSpendingFee")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("FeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_fee_rate")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("confirmation_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token attribute attr-name"}},[t._v("#[tokio::main]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("async")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" fee_estimator "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyAppFeeEstimator")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Err")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("update_fees")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("await")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to update fees: {}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Example of calling 'get_est_sat_per_1000_weight' with a specific confirmation target")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" high_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OnChainSweep")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" low_fee_target "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ConfirmationTarget")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MinAllowedAnchorChannelRemoteFee")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("high_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("println!")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Feerate for {:?}: {:?}"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fee_estimator"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_est_sat_per_1000_weight")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low_fee_target"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/57.c8a60d35.js b/assets/js/57.cbcc9b30.js similarity index 94% rename from assets/js/57.c8a60d35.js rename to assets/js/57.cbcc9b30.js index 5223b51a3..5fd616d54 100644 --- a/assets/js/57.c8a60d35.js +++ b/assets/js/57.cbcc9b30.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[57],{427:function(t,n,e){"use strict";e.r(n);var o=e(7),a=Object(o.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"blockchain-data"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#blockchain-data"}},[t._v("#")]),t._v(" Blockchain Data")]),t._v(" "),n("p",[t._v("LDK provides a simple "),n("code",[t._v("block_connected")]),t._v("/"),n("code",[t._v("block_disconnected")]),t._v(" API which you pass block headers and transaction information to. LDK also provides an API for getting information about transactions it wishes to be informed of, which is compatible with Electrum server requests/neutrino filtering/etc.")]),t._v(" "),n("p",[n("a",{attrs:{href:"https://lightningdevkit.org/blockchain_data/introduction/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Blockchain Data Guide"),n("OutboundLink")],1)]),t._v(" "),n("p",[n("a",{attrs:{href:"https://github.com/rust-bitcoin/rust-lightning/tree/main/lightning-block-sync",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample module in Rust"),n("OutboundLink")],1)])])}),[],!1,null,null,null);n.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[57],{425:function(t,n,e){"use strict";e.r(n);var o=e(7),a=Object(o.a)({},(function(){var t=this,n=t._self._c;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"blockchain-data"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#blockchain-data"}},[t._v("#")]),t._v(" Blockchain Data")]),t._v(" "),n("p",[t._v("LDK provides a simple "),n("code",[t._v("block_connected")]),t._v("/"),n("code",[t._v("block_disconnected")]),t._v(" API which you pass block headers and transaction information to. LDK also provides an API for getting information about transactions it wishes to be informed of, which is compatible with Electrum server requests/neutrino filtering/etc.")]),t._v(" "),n("p",[n("a",{attrs:{href:"https://lightningdevkit.org/blockchain_data/introduction/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Blockchain Data Guide"),n("OutboundLink")],1)]),t._v(" "),n("p",[n("a",{attrs:{href:"https://github.com/rust-bitcoin/rust-lightning/tree/main/lightning-block-sync",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample module in Rust"),n("OutboundLink")],1)])])}),[],!1,null,null,null);n.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/58.d9227362.js b/assets/js/58.b175b9b9.js similarity index 98% rename from assets/js/58.d9227362.js rename to assets/js/58.b175b9b9.js index 0049d7a9f..2537dee48 100644 --- a/assets/js/58.d9227362.js +++ b/assets/js/58.b175b9b9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[58],{428:function(t,e,n){"use strict";n.r(e);var a=n(7),o=Object(a.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"introduction"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),e("p",[t._v("Lightning Development Kit (LDK) is a full and completely standalone Lightning implementation with supporting modules enabling greater flexibility.")]),t._v(" "),e("p",[t._v("You can build a Lightning node without needing to worry about getting all of the Lightning state machine, routing, and on-chain punishment code (and other chain interactions) exactly correct. LDK tends to be suitable for use cases where a degree of customization is desired, e.g. your own chain sync, your own key management and/or your own storage/backup logic.")]),t._v(" "),e("p",[t._v("Our "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("sample node"),e("OutboundLink")],1),t._v(" showcases how LDK can be customised. It fetches blockchain data and transacts on-chain via Bitcoin Core RPC/REST. The individual components of the sample are composable. For example, the sample writes channel state to the local filesystem, but this component could be replaced with one that writes this data to the cloud or to multiple locations. You can pick the off-the-shelf parts you want and replace the rest.")]),t._v(" "),e("p",[t._v("To start building a node with LDK "),e("RouterLink",{attrs:{to:"/building-a-node-with-ldk/introduction/"}},[t._v("click here.")])],1),t._v(" "),e("h2",{attrs:{id:"references"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#references"}},[t._v("#")]),t._v(" References")]),t._v(" "),e("h3",{attrs:{id:"rust-documentation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#rust-documentation"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://docs.rs/lightning",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Documentation"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("These provide the most searchable and comprehensive documentation on LDK.\nIf you're using Java and want more information on any method/struct/etc., searching\nthe Rust docs for the Rust version of that struct/method is your best bet.")]),t._v(" "),e("h3",{attrs:{id:"swift-ldk-documentation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#swift-ldk-documentation"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://github.com/arik-so/SwiftLightning/tree/master/Documentation",target:"_blank",rel:"noopener noreferrer"}},[t._v("Swift LDK Documentation"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("These docs are mainly geared towards how Swift could call LDK C bindings directly, but still may\nprovide a useful overview of Rust Lightning in the context of language bindings.")]),t._v(" "),e("h3",{attrs:{id:"rust-sample-node"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#rust-sample-node"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Sample Node"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("The sample serves as a complete reference for constructing a Lightning node with\nthe LDK. This is a good starting point if you want a self-guided tour!")]),t._v(" "),e("h3",{attrs:{id:"architecture"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#architecture"}},[t._v("#")]),t._v(" "),e("RouterLink",{attrs:{to:"/introduction/architecture/"}},[t._v("Architecture")])],1),t._v(" "),e("p",[t._v("Gives a high-level organization of LDK and how the pieces fit together. Variations of this diagram\nare used throughout the site. This is the primary source and is still a work in progress.")])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[58],{426:function(t,e,n){"use strict";n.r(e);var a=n(7),o=Object(a.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"introduction"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),e("p",[t._v("Lightning Development Kit (LDK) is a full and completely standalone Lightning implementation with supporting modules enabling greater flexibility.")]),t._v(" "),e("p",[t._v("You can build a Lightning node without needing to worry about getting all of the Lightning state machine, routing, and on-chain punishment code (and other chain interactions) exactly correct. LDK tends to be suitable for use cases where a degree of customization is desired, e.g. your own chain sync, your own key management and/or your own storage/backup logic.")]),t._v(" "),e("p",[t._v("Our "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("sample node"),e("OutboundLink")],1),t._v(" showcases how LDK can be customised. It fetches blockchain data and transacts on-chain via Bitcoin Core RPC/REST. The individual components of the sample are composable. For example, the sample writes channel state to the local filesystem, but this component could be replaced with one that writes this data to the cloud or to multiple locations. You can pick the off-the-shelf parts you want and replace the rest.")]),t._v(" "),e("p",[t._v("To start building a node with LDK "),e("RouterLink",{attrs:{to:"/building-a-node-with-ldk/introduction/"}},[t._v("click here.")])],1),t._v(" "),e("h2",{attrs:{id:"references"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#references"}},[t._v("#")]),t._v(" References")]),t._v(" "),e("h3",{attrs:{id:"rust-documentation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#rust-documentation"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://docs.rs/lightning",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Documentation"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("These provide the most searchable and comprehensive documentation on LDK.\nIf you're using Java and want more information on any method/struct/etc., searching\nthe Rust docs for the Rust version of that struct/method is your best bet.")]),t._v(" "),e("h3",{attrs:{id:"swift-ldk-documentation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#swift-ldk-documentation"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://github.com/arik-so/SwiftLightning/tree/master/Documentation",target:"_blank",rel:"noopener noreferrer"}},[t._v("Swift LDK Documentation"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("These docs are mainly geared towards how Swift could call LDK C bindings directly, but still may\nprovide a useful overview of Rust Lightning in the context of language bindings.")]),t._v(" "),e("h3",{attrs:{id:"rust-sample-node"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#rust-sample-node"}},[t._v("#")]),t._v(" "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust Sample Node"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("The sample serves as a complete reference for constructing a Lightning node with\nthe LDK. This is a good starting point if you want a self-guided tour!")]),t._v(" "),e("h3",{attrs:{id:"architecture"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#architecture"}},[t._v("#")]),t._v(" "),e("RouterLink",{attrs:{to:"/introduction/architecture/"}},[t._v("Architecture")])],1),t._v(" "),e("p",[t._v("Gives a high-level organization of LDK and how the pieces fit together. Variations of this diagram\nare used throughout the site. This is the primary source and is still a work in progress.")])])}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/59.4597ca6d.js b/assets/js/59.26a01d4b.js similarity index 93% rename from assets/js/59.4597ca6d.js rename to assets/js/59.26a01d4b.js index b210e51bf..84891c713 100644 --- a/assets/js/59.4597ca6d.js +++ b/assets/js/59.26a01d4b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[59],{429:function(t,e,n){"use strict";n.r(e);var o=n(7),i=Object(o.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"networking"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#networking"}},[this._v("#")]),this._v(" Networking")]),this._v(" "),t("p",[this._v("To enable you to run a full Lightning node on an embedded machine, LDK doesn't specify exactly how to connect to another node at all! The default implementation uses TCP sockets, but, e.g., if you wanted to run your full Lightning node on a hardware wallet, you could, by piping the Lightning network messages over USB/serial and then sending them in a TCP socket from another machine.")]),this._v(" "),t("p",[this._v("Learn more about "),t("RouterLink",{attrs:{to:"/building-a-node-with-ldk/connect-to-peers/"}},[this._v("connect to peers.")])],1)])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[59],{427:function(t,e,n){"use strict";n.r(e);var o=n(7),i=Object(o.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"networking"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#networking"}},[this._v("#")]),this._v(" Networking")]),this._v(" "),t("p",[this._v("To enable you to run a full Lightning node on an embedded machine, LDK doesn't specify exactly how to connect to another node at all! The default implementation uses TCP sockets, but, e.g., if you wanted to run your full Lightning node on a hardware wallet, you could, by piping the Lightning network messages over USB/serial and then sending them in a TCP socket from another machine.")]),this._v(" "),t("p",[this._v("Learn more about "),t("RouterLink",{attrs:{to:"/building-a-node-with-ldk/connect-to-peers/"}},[this._v("connect to peers.")])],1)])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/7.18672f7a.js b/assets/js/6.e4bbfe71.js similarity index 95% rename from assets/js/7.18672f7a.js rename to assets/js/6.e4bbfe71.js index 2092a91c6..5b8325a45 100644 --- a/assets/js/7.18672f7a.js +++ b/assets/js/6.e4bbfe71.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7,8],{251:function(t,e){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},254:function(t,e,n){},255:function(t,e,n){},256:function(t,e,n){},257:function(t,e,n){},258:function(t,e,n){"use strict";n(254)},260:function(t,e,n){"use strict";var r={name:"PostMeta",props:["post"],filters:{capitalize:n(251).capitalize}},i=(n(258),n(7)),s=Object(i.a)(r,(function(){var t=this,e=t._self._c;return e("p",{staticClass:"meta"},[t._v("\n By\n\n "),t._l(t.post.frontmatter.authors,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/author/"+n}},[t._v(t._s(n))]),r!=t.post.frontmatter.authors.length-1?e("span",[t._v(", ")]):t._e()],1)})),t._v("\n\n on\n\n "+t._s(new Date(t.post.frontmatter.date).getMonth()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getDate()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getFullYear())+"\n\n - Tags:\n\n "),t._l(t.post.frontmatter.tags,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/tags/"+n}},[t._v(t._s(t._f("capitalize")(n)))]),r!=t.post.frontmatter.tags.length-1?[t._v(", ")]:t._e()],2)}))],2)}),[],!1,null,"0f148fb8",null);e.a=s.exports},265:function(t,e,n){"use strict";n(255)},266:function(t,e,n){"use strict";n(256)},267:function(t,e,n){var r=n(104),i=n(97),s=n(268),a=n(272);t.exports=function(t,e){if(null==t)return{};var n=r(a(t),(function(t){return[t]}));return e=i(e),s(t,n,(function(t,n){return e(t,n[0])}))}},268:function(t,e,n){var r=n(52),i=n(269),s=n(47);t.exports=function(t,e,n){for(var a=-1,o=e.length,u={};++a({comp:null}),computed:{page(){return this.$pagination.paginationIndex+1}},mounted(){n.e(4).then(n.t.bind(null,377,7)).then(t=>{this.comp=t.default})},methods:{clickCallback(t){const e=this.$pagination.getSpecificPageLink(t-1);this.$router.push(e)}}}),a=(n(265),n(7)),o=Object(a.a)(s,(function(){var t=this._self._c;return this.comp?t(this.comp,{tag:"component",attrs:{value:this.page,"page-count":this.$pagination.length,"click-handler":this.clickCallback,"prev-text":this.$pagination.prevText,"next-text":this.$pagination.nextText,"container-class":"pagination","page-class":"page-item"}}):this._e()}),[],!1,null,null,null).exports,u=(n(266),Object(a.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"pagination simple-pagination"},[t.$pagination.hasPrev?e("router-link",{attrs:{to:t.$pagination.prevLink}},[t._v("\n "+t._s(t.$pagination.prevText)+"\n ")]):t._e(),t._v(" "),t.$pagination.hasNext?e("router-link",{attrs:{to:t.$pagination.nextLink}},[t._v("\n "+t._s(t.$pagination.nextText)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports,n(24)),p=n.n(u),c=n(267),l=n.n(c),f={props:{title:{type:[String,Function],required:!1},issueId:{type:[String,Number],required:!1},options:{type:Object,required:!1},shortname:{type:String,required:!1},identifier:{type:String,required:!1},url:{type:String,required:!1},remote_auth_s3:{type:String,required:!1},api_key:{type:String,required:!1},sso_config:{type:Object,required:!1},language:{type:String,required:!1}},computed:{propsWithoutEmptyProperties(){return l()(this.$props,p.a)},commentProps(){return Object.assign({},this.propsWithoutEmptyProperties,this.$frontmatter.comment)},vssueProps(){return Object.assign({title:this.$page.title},this.commentProps)},disqusProps(){return Object.assign({identifier:this.$page.key},this.commentProps)}}},g=(Object(a.a)(f,(function(){var t=this._self._c;return"vssue"===this.$service.comment.service?t("Vssue",this._b({},"Vssue",this.vssueProps,!1)):"disqus"===this.$service.comment.service?t("Disqus",this._b({},"Disqus",this.disqusProps,!1)):this._e()}),[],!1,null,null,null).exports,n(251)),h={name:"IndexPost",components:{LayoutWrap:r.a,Pagination:o,PostMeta:i.a},props:["items","title"],computed:{posts(){return this.items||this.$pagination.pages.sort((t,e)=>new Date(e.frontmatter.date)-new Date(t.frontmatter.date))}},filters:{capitalize:g.capitalize}},v=(n(278),Object(a.a)(h,(function(){var t=this,e=t._self._c;return e("LayoutWrap",[e("main",{staticClass:"page"},[e("div",{staticClass:"theme-default-content"},[e("h1",[t._v(t._s(t.title||"Blog"))]),t._v(" "),t._l(t.posts,(function(n){return e("div",{key:n.path},[e("h2",{staticClass:"index-post-title"},[e("router-link",{attrs:{to:n.path}},[t._v(t._s(n.title||n.frontmatter.title))])],1),t._v(" "),e("PostMeta",{attrs:{post:n}}),t._v(" "),n.frontmatter.coverImage?e("router-link",{attrs:{to:n.path}},[e("img",{staticClass:"cover-image",attrs:{src:n.frontmatter.coverImage}})]):t._e(),t._v(" "),e("hr")],1)})),t._v(" "),t.$pagination.length>1?e("Pagination"):t._e()],2)])])}),[],!1,null,"073f78a2",null));e.default=v.exports},382:function(t,e,n){"use strict";n.r(e);var r=n(281),i=n(251),s={name:"FrontmatterPagination",components:{IndexPost:r.default},computed:{title(){return this.$page.path.startsWith("/blog/tags/")?"Posts tagged with "+Object(i.capitalize)(this.$page.frontmatter.title):"Posts by "+this.$page.frontmatter.title}}},a=n(7),o=Object(a.a)(s,(function(){return(0,this._self._c)("IndexPost",{attrs:{title:this.title}})}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[6,8],{251:function(t,e){t.exports={capitalize:t=>t.replace(/^\w/,t=>t.toUpperCase())}},254:function(t,e,n){},255:function(t,e,n){},256:function(t,e,n){},257:function(t,e,n){},258:function(t,e,n){"use strict";n(254)},260:function(t,e,n){"use strict";var r={name:"PostMeta",props:["post"],filters:{capitalize:n(251).capitalize}},i=(n(258),n(7)),s=Object(i.a)(r,(function(){var t=this,e=t._self._c;return e("p",{staticClass:"meta"},[t._v("\n By\n\n "),t._l(t.post.frontmatter.authors,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/author/"+n}},[t._v(t._s(n))]),r!=t.post.frontmatter.authors.length-1?e("span",[t._v(", ")]):t._e()],1)})),t._v("\n\n on\n\n "+t._s(new Date(t.post.frontmatter.date).getMonth()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getDate()+1)+"/"+t._s(new Date(t.post.frontmatter.date).getFullYear())+"\n\n - Tags:\n\n "),t._l(t.post.frontmatter.tags,(function(n,r){return e("span",{key:n},[e("router-link",{staticClass:"meta-link",attrs:{to:"/blog/tags/"+n}},[t._v(t._s(t._f("capitalize")(n)))]),r!=t.post.frontmatter.tags.length-1?[t._v(", ")]:t._e()],2)}))],2)}),[],!1,null,"0f148fb8",null);e.a=s.exports},265:function(t,e,n){"use strict";n(255)},266:function(t,e,n){"use strict";n(256)},267:function(t,e,n){var r=n(104),i=n(97),s=n(268),a=n(272);t.exports=function(t,e){if(null==t)return{};var n=r(a(t),(function(t){return[t]}));return e=i(e),s(t,n,(function(t,n){return e(t,n[0])}))}},268:function(t,e,n){var r=n(52),i=n(269),s=n(47);t.exports=function(t,e,n){for(var a=-1,o=e.length,u={};++a({comp:null}),computed:{page(){return this.$pagination.paginationIndex+1}},mounted(){n.e(4).then(n.t.bind(null,375,7)).then(t=>{this.comp=t.default})},methods:{clickCallback(t){const e=this.$pagination.getSpecificPageLink(t-1);this.$router.push(e)}}}),a=(n(265),n(7)),o=Object(a.a)(s,(function(){var t=this._self._c;return this.comp?t(this.comp,{tag:"component",attrs:{value:this.page,"page-count":this.$pagination.length,"click-handler":this.clickCallback,"prev-text":this.$pagination.prevText,"next-text":this.$pagination.nextText,"container-class":"pagination","page-class":"page-item"}}):this._e()}),[],!1,null,null,null).exports,u=(n(266),Object(a.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"pagination simple-pagination"},[t.$pagination.hasPrev?e("router-link",{attrs:{to:t.$pagination.prevLink}},[t._v("\n "+t._s(t.$pagination.prevText)+"\n ")]):t._e(),t._v(" "),t.$pagination.hasNext?e("router-link",{attrs:{to:t.$pagination.nextLink}},[t._v("\n "+t._s(t.$pagination.nextText)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports,n(24)),p=n.n(u),c=n(267),l=n.n(c),f={props:{title:{type:[String,Function],required:!1},issueId:{type:[String,Number],required:!1},options:{type:Object,required:!1},shortname:{type:String,required:!1},identifier:{type:String,required:!1},url:{type:String,required:!1},remote_auth_s3:{type:String,required:!1},api_key:{type:String,required:!1},sso_config:{type:Object,required:!1},language:{type:String,required:!1}},computed:{propsWithoutEmptyProperties(){return l()(this.$props,p.a)},commentProps(){return Object.assign({},this.propsWithoutEmptyProperties,this.$frontmatter.comment)},vssueProps(){return Object.assign({title:this.$page.title},this.commentProps)},disqusProps(){return Object.assign({identifier:this.$page.key},this.commentProps)}}},g=(Object(a.a)(f,(function(){var t=this._self._c;return"vssue"===this.$service.comment.service?t("Vssue",this._b({},"Vssue",this.vssueProps,!1)):"disqus"===this.$service.comment.service?t("Disqus",this._b({},"Disqus",this.disqusProps,!1)):this._e()}),[],!1,null,null,null).exports,n(251)),h={name:"IndexPost",components:{LayoutWrap:r.a,Pagination:o,PostMeta:i.a},props:["items","title"],computed:{posts(){return this.items||this.$pagination.pages.sort((t,e)=>new Date(e.frontmatter.date)-new Date(t.frontmatter.date))}},filters:{capitalize:g.capitalize}},v=(n(278),Object(a.a)(h,(function(){var t=this,e=t._self._c;return e("LayoutWrap",[e("main",{staticClass:"page"},[e("div",{staticClass:"theme-default-content"},[e("h1",[t._v(t._s(t.title||"Blog"))]),t._v(" "),t._l(t.posts,(function(n){return e("div",{key:n.path},[e("h2",{staticClass:"index-post-title"},[e("router-link",{attrs:{to:n.path}},[t._v(t._s(n.title||n.frontmatter.title))])],1),t._v(" "),e("PostMeta",{attrs:{post:n}}),t._v(" "),n.frontmatter.coverImage?e("router-link",{attrs:{to:n.path}},[e("img",{staticClass:"cover-image",attrs:{src:n.frontmatter.coverImage}})]):t._e(),t._v(" "),e("hr")],1)})),t._v(" "),t.$pagination.length>1?e("Pagination"):t._e()],2)])])}),[],!1,null,"073f78a2",null));e.default=v.exports},380:function(t,e,n){"use strict";n.r(e);var r=n(282),i=n(251),s={name:"FrontmatterPagination",components:{IndexPost:r.default},computed:{title(){return this.$page.path.startsWith("/blog/tags/")?"Posts tagged with "+Object(i.capitalize)(this.$page.frontmatter.title):"Posts by "+this.$page.frontmatter.title}}},a=n(7),o=Object(a.a)(s,(function(){return(0,this._self._c)("IndexPost",{attrs:{title:this.title}})}),[],!1,null,null,null);e.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/60.97c17a2e.js b/assets/js/60.0ad4729d.js similarity index 94% rename from assets/js/60.97c17a2e.js rename to assets/js/60.0ad4729d.js index 6351ea85e..6829a5ebf 100644 --- a/assets/js/60.97c17a2e.js +++ b/assets/js/60.0ad4729d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[60],{433:function(t,e,r){"use strict";r.r(e);var n=r(7),s=Object(n.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"persistent-storage"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#persistent-storage"}},[t._v("#")]),t._v(" Persistent Storage")]),t._v(" "),e("p",[t._v("You can store the channel state any way you want - whether Google Drive/iCloud, a local disk, any key-value store/database/a remote server, or any combination of them - LDK provides a clean API, where objects can be serialized into simple binary blobs, and stored in any way you wish.")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("Persist")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("a",{attrs:{href:"https://github.com/rust-bitcoin/rust-lightning/tree/main/lightning-persister",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample module in Rust"),e("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[60],{429:function(t,e,r){"use strict";r.r(e);var n=r(7),s=Object(n.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"persistent-storage"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#persistent-storage"}},[t._v("#")]),t._v(" Persistent Storage")]),t._v(" "),e("p",[t._v("You can store the channel state any way you want - whether Google Drive/iCloud, a local disk, any key-value store/database/a remote server, or any combination of them - LDK provides a clean API, where objects can be serialized into simple binary blobs, and stored in any way you wish.")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/latest/lightning/chain/chainmonitor/trait.Persist.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("Persist")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("a",{attrs:{href:"https://github.com/rust-bitcoin/rust-lightning/tree/main/lightning-persister",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sample module in Rust"),e("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/61.02b8c9cb.js b/assets/js/61.b4bc421f.js similarity index 94% rename from assets/js/61.02b8c9cb.js rename to assets/js/61.b4bc421f.js index 0a3872586..90a7d68bb 100644 --- a/assets/js/61.02b8c9cb.js +++ b/assets/js/61.b4bc421f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[61],{431:function(e,t,n){"use strict";n.r(t);var a=n(7),r=Object(a.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"private-key-management"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#private-key-management"}},[e._v("#")]),e._v(" Private Key Management")]),e._v(" "),t("p",[e._v("LDK provides a default implementation for key management, but you can choose to provide private keys to LDK in any way you wish following a simple API. LDK even supports a generic API for signing transactions, allowing you to run LDK without any private keys in memory and/or putting private keys only on hardware wallets.")]),e._v(" "),t("p",[e._v("While LDK's default implementation is currently located within the "),t("code",[e._v("rust-lightning")]),e._v(" crate, it is still considered a sample module.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK's "),t("code",[e._v("KeysManager")]),e._v(" docs"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[61],{433:function(e,t,n){"use strict";n.r(t);var a=n(7),r=Object(a.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"private-key-management"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#private-key-management"}},[e._v("#")]),e._v(" Private Key Management")]),e._v(" "),t("p",[e._v("LDK provides a default implementation for key management, but you can choose to provide private keys to LDK in any way you wish following a simple API. LDK even supports a generic API for signing transactions, allowing you to run LDK without any private keys in memory and/or putting private keys only on hardware wallets.")]),e._v(" "),t("p",[e._v("While LDK's default implementation is currently located within the "),t("code",[e._v("rust-lightning")]),e._v(" crate, it is still considered a sample module.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("LDK's "),t("code",[e._v("KeysManager")]),e._v(" docs"),t("OutboundLink")],1),e._v(".")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/62.f2d7849a.js b/assets/js/62.d4954330.js similarity index 93% rename from assets/js/62.f2d7849a.js rename to assets/js/62.d4954330.js index 3163d4b2f..b28244e5d 100644 --- a/assets/js/62.f2d7849a.js +++ b/assets/js/62.d4954330.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[62],{432:function(e,t,n){"use strict";n.r(t);var r=n(7),a=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"random-number-generation"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#random-number-generation"}},[e._v("#")]),e._v(" Random Number Generation")]),e._v(" "),t("p",[e._v("LDK aims to make no system calls, it is therefore restricted from generating its own randomness.")]),e._v(" "),t("p",[e._v("The sample node implementation uses Rust's "),t("code",[e._v("rand")]),e._v(" crate "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/main.rs#L464-L465",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(" and elsewhere.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[62],{430:function(e,t,n){"use strict";n.r(t);var r=n(7),a=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"random-number-generation"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#random-number-generation"}},[e._v("#")]),e._v(" Random Number Generation")]),e._v(" "),t("p",[e._v("LDK aims to make no system calls, it is therefore restricted from generating its own randomness.")]),e._v(" "),t("p",[e._v("The sample node implementation uses Rust's "),t("code",[e._v("rand")]),e._v(" crate "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/main.rs#L464-L465",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(" and elsewhere.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/63.0775b4d9.js b/assets/js/63.b031816d.js similarity index 98% rename from assets/js/63.0775b4d9.js rename to assets/js/63.b031816d.js index f6a22b82d..7dd098d52 100644 --- a/assets/js/63.0775b4d9.js +++ b/assets/js/63.b031816d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[63],{434:function(t,e,r){"use strict";r.r(e);var a=r(7),n=Object(a.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"transactions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transactions"}},[t._v("#")]),t._v(" Transactions")]),t._v(" "),e("h2",{attrs:{id:"transaction-filtering"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transaction-filtering"}},[t._v("#")]),t._v(" Transaction Filtering")]),t._v(" "),e("p",[t._v("Clients running a light client may wish to filter for transactions on a separate server, in which case LDK will tell them about transactions to filter for.")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("Filter")]),t._v(" API reference"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("More information is available in the "),e("a",{attrs:{href:"/blockchain_data/introduction"}},[t._v("Blockchain Data guide")]),t._v(".")]),t._v(" "),e("h2",{attrs:{id:"fee-estimation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#fee-estimation"}},[t._v("#")]),t._v(" Fee Estimation")]),t._v(" "),e("p",[t._v("LDK let's you decide your source for fee estimation. This could be Bitcoin Core's fee estimation through "),e("code",[t._v("estimatesmartfee")]),t._v(" RPC method or third-party "),e("a",{attrs:{href:"https://b10c.me/blog/003-a-list-of-public-bitcoin-feerate-estimation-apis/",target:"_blank",rel:"noopener noreferrer"}},[t._v("fee-estimators"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("FeeEstimator")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("LDK's sample node implementation uses Bitcoin Core's fee estimation API "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/bitcoind_client.rs#L98-L154",target:"_blank",rel:"noopener noreferrer"}},[t._v("here."),e("OutboundLink")],1)]),t._v(" "),e("h2",{attrs:{id:"transaction-broadcasting"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transaction-broadcasting"}},[t._v("#")]),t._v(" Transaction Broadcasting")]),t._v(" "),e("p",[t._v("You can broadcast transactions in a few ways, using Bitcoin core or other "),e("a",{attrs:{href:"https://en.bitcoin.it/wiki/Transaction_broadcasting",target:"_blank",rel:"noopener noreferrer"}},[t._v("external API's"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("BroadcasterInterface")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("LDK's sample node implementation uses Bitcoin Core's transaction broadcasting API "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/bitcoind_client.rs#L235-L257",target:"_blank",rel:"noopener noreferrer"}},[t._v("here."),e("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[63],{431:function(t,e,r){"use strict";r.r(e);var a=r(7),n=Object(a.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"transactions"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transactions"}},[t._v("#")]),t._v(" Transactions")]),t._v(" "),e("h2",{attrs:{id:"transaction-filtering"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transaction-filtering"}},[t._v("#")]),t._v(" Transaction Filtering")]),t._v(" "),e("p",[t._v("Clients running a light client may wish to filter for transactions on a separate server, in which case LDK will tell them about transactions to filter for.")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/trait.Filter.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("Filter")]),t._v(" API reference"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("More information is available in the "),e("a",{attrs:{href:"/blockchain_data/introduction"}},[t._v("Blockchain Data guide")]),t._v(".")]),t._v(" "),e("h2",{attrs:{id:"fee-estimation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#fee-estimation"}},[t._v("#")]),t._v(" Fee Estimation")]),t._v(" "),e("p",[t._v("LDK let's you decide your source for fee estimation. This could be Bitcoin Core's fee estimation through "),e("code",[t._v("estimatesmartfee")]),t._v(" RPC method or third-party "),e("a",{attrs:{href:"https://b10c.me/blog/003-a-list-of-public-bitcoin-feerate-estimation-apis/",target:"_blank",rel:"noopener noreferrer"}},[t._v("fee-estimators"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("FeeEstimator")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("LDK's sample node implementation uses Bitcoin Core's fee estimation API "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/bitcoind_client.rs#L98-L154",target:"_blank",rel:"noopener noreferrer"}},[t._v("here."),e("OutboundLink")],1)]),t._v(" "),e("h2",{attrs:{id:"transaction-broadcasting"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#transaction-broadcasting"}},[t._v("#")]),t._v(" Transaction Broadcasting")]),t._v(" "),e("p",[t._v("You can broadcast transactions in a few ways, using Bitcoin core or other "),e("a",{attrs:{href:"https://en.bitcoin.it/wiki/Transaction_broadcasting",target:"_blank",rel:"noopener noreferrer"}},[t._v("external API's"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("LDK's "),e("code",[t._v("BroadcasterInterface")]),t._v(" docs"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("LDK's sample node implementation uses Bitcoin Core's transaction broadcasting API "),e("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/bitcoind_client.rs#L235-L257",target:"_blank",rel:"noopener noreferrer"}},[t._v("here."),e("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/64.16b2e10e.js b/assets/js/64.d6484b1d.js similarity index 98% rename from assets/js/64.16b2e10e.js rename to assets/js/64.d6484b1d.js index c511849b2..ddb032076 100644 --- a/assets/js/64.16b2e10e.js +++ b/assets/js/64.d6484b1d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[64],{435:function(t,e,n){"use strict";n.r(e);var i=n(7),a=Object(i.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"use-cases-for-ldk"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#use-cases-for-ldk"}},[t._v("#")]),t._v(" Use Cases for LDK")]),t._v(" "),e("p",[t._v("The standard Lightning use case is running a standalone node on one's laptop.\nHere's some other use cases that LDK supports.")]),t._v(" "),e("h2",{attrs:{id:"mobile-devices"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#mobile-devices"}},[t._v("#")]),t._v(" Mobile Devices")]),t._v(" "),e("p",[t._v("Mobile devices with Lightning have unique requirements often not well served by\ntoday's Lightning ecosystem. Not only do they need to operate with minimal\nfootprint, they also have intermittent data access and cannot shutdown safely.\nMore importantly, many existing wallets already have business logic to handle\nblockchain data, keys, and storage, and do not wish to duplicate much of that\nlogic to integrate Lightning (at worst fetching the blockchain twice). LDK\noffers a flexible API to allow users to integrate Lightning with their own keys,\nblockchain data, and storage. To allow full flexibility in footprint, the API\nsupports routing data being fetched via the Lightning P2P protocol, an external\nservice, or routes can be calculated off-device. It also provides cross-platform\ncompatibility for free, allowing synchronization of Lightning state across\ndevices and, as long as there is protection from simultaneous updates, users to\naccess their wallet on any device. See the "),e("a",{attrs:{href:"../architecture"}},[t._v("architecure")]),t._v(" page for more\ndetails on the interfaces LDK provides for integration.")]),t._v(" "),e("h2",{attrs:{id:"hsms-hardware-security-modules"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#hsms-hardware-security-modules"}},[t._v("#")]),t._v(" HSMs (Hardware Security Modules)")]),t._v(" "),e("p",[t._v("LDK Supports various HSM configurations. In conjunction with the "),e("a",{attrs:{href:"https://vls.tech/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Validating Lightning Signer"),e("OutboundLink")],1),t._v("project, an external HSM can be\nused to verify most protocol details about states before signing, ensuring host\ncompromise cannot steal funds by broadcasting revoked states. For nodes seeking\na higher level of assurance, the entire LDK channel state machine can\nbe run on an offline device, communicating with the outside world via a proxy\nhost which maintains TCP connections with peers. Such a configuration ensures\nall details of the Lightning protocol are enforced without consideration of host\ncompromise.")]),t._v(" "),e("h2",{attrs:{id:"production-lightning-nodes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#production-lightning-nodes"}},[t._v("#")]),t._v(" Production Lightning Nodes")]),t._v(" "),e("p",[t._v("Many large Bitcoin transactors have large amounts of custom-built infrastructure\nfor interacting with the Bitcoin blockchain. Such tight integration with\nbusiness logic may be difficult with existing Lightning implementations focusing\non standalone operation. For such transactors, LDK offers the possibility of\nintegrating a library in their native runtime, storing and handling Lightning\ndata and events in the same way they do blockchain events.")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[64],{432:function(t,e,n){"use strict";n.r(e);var i=n(7),a=Object(i.a)({},(function(){var t=this,e=t._self._c;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"use-cases-for-ldk"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#use-cases-for-ldk"}},[t._v("#")]),t._v(" Use Cases for LDK")]),t._v(" "),e("p",[t._v("The standard Lightning use case is running a standalone node on one's laptop.\nHere's some other use cases that LDK supports.")]),t._v(" "),e("h2",{attrs:{id:"mobile-devices"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#mobile-devices"}},[t._v("#")]),t._v(" Mobile Devices")]),t._v(" "),e("p",[t._v("Mobile devices with Lightning have unique requirements often not well served by\ntoday's Lightning ecosystem. Not only do they need to operate with minimal\nfootprint, they also have intermittent data access and cannot shutdown safely.\nMore importantly, many existing wallets already have business logic to handle\nblockchain data, keys, and storage, and do not wish to duplicate much of that\nlogic to integrate Lightning (at worst fetching the blockchain twice). LDK\noffers a flexible API to allow users to integrate Lightning with their own keys,\nblockchain data, and storage. To allow full flexibility in footprint, the API\nsupports routing data being fetched via the Lightning P2P protocol, an external\nservice, or routes can be calculated off-device. It also provides cross-platform\ncompatibility for free, allowing synchronization of Lightning state across\ndevices and, as long as there is protection from simultaneous updates, users to\naccess their wallet on any device. See the "),e("a",{attrs:{href:"../architecture"}},[t._v("architecure")]),t._v(" page for more\ndetails on the interfaces LDK provides for integration.")]),t._v(" "),e("h2",{attrs:{id:"hsms-hardware-security-modules"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#hsms-hardware-security-modules"}},[t._v("#")]),t._v(" HSMs (Hardware Security Modules)")]),t._v(" "),e("p",[t._v("LDK Supports various HSM configurations. In conjunction with the "),e("a",{attrs:{href:"https://vls.tech/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Validating Lightning Signer"),e("OutboundLink")],1),t._v("project, an external HSM can be\nused to verify most protocol details about states before signing, ensuring host\ncompromise cannot steal funds by broadcasting revoked states. For nodes seeking\na higher level of assurance, the entire LDK channel state machine can\nbe run on an offline device, communicating with the outside world via a proxy\nhost which maintains TCP connections with peers. Such a configuration ensures\nall details of the Lightning protocol are enforced without consideration of host\ncompromise.")]),t._v(" "),e("h2",{attrs:{id:"production-lightning-nodes"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#production-lightning-nodes"}},[t._v("#")]),t._v(" Production Lightning Nodes")]),t._v(" "),e("p",[t._v("Many large Bitcoin transactors have large amounts of custom-built infrastructure\nfor interacting with the Bitcoin blockchain. Such tight integration with\nbusiness logic may be difficult with existing Lightning implementations focusing\non standalone operation. For such transactors, LDK offers the possibility of\nintegrating a library in their native runtime, storing and handling Lightning\ndata and events in the same way they do blockchain events.")])])}),[],!1,null,null,null);e.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/65.fb737b56.js b/assets/js/65.3e04e647.js similarity index 96% rename from assets/js/65.fb737b56.js rename to assets/js/65.3e04e647.js index 2f1d728aa..d45f0e34a 100644 --- a/assets/js/65.fb737b56.js +++ b/assets/js/65.3e04e647.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{436:function(e,t,a){"use strict";a.r(t);var n=a(7),i=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"wallet-management"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#wallet-management"}},[e._v("#")]),e._v(" Wallet Management")]),e._v(" "),t("p",[e._v('LDK owns on-chain funds as long as they are claimable as a part of a Lightning output which can be contested - once a channel is closed and all on-chain outputs are spendable only by you, LDK provides you notifications that a UTXO is "yours" again and it is up to you to spend it as you wish.')]),e._v(" "),t("p",[e._v("Additionally, channel funding is accomplished with a generic API which notifies users of the output which needs to appear on-chain, which they can then create a transaction for. Once a transaction is created, LDK handles the rest. This is a large part of our API's goals - making it easier to integrate Lightning into existing on-chain wallets which have their own on-chain logic - without needing to move funds in and out of a separate Lightning wallet with on-chain transactions and a separate private key system.")]),e._v(" "),t("p",[e._v("LDK does not currently provide a sample wallet module, but its sample node implementation uses Bitcoin Core's wallet for UTXO management e.g. "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/main.rs#L245-L260",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1)])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{434:function(e,t,a){"use strict";a.r(t);var n=a(7),i=Object(n.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"wallet-management"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#wallet-management"}},[e._v("#")]),e._v(" Wallet Management")]),e._v(" "),t("p",[e._v('LDK owns on-chain funds as long as they are claimable as a part of a Lightning output which can be contested - once a channel is closed and all on-chain outputs are spendable only by you, LDK provides you notifications that a UTXO is "yours" again and it is up to you to spend it as you wish.')]),e._v(" "),t("p",[e._v("Additionally, channel funding is accomplished with a generic API which notifies users of the output which needs to appear on-chain, which they can then create a transaction for. Once a transaction is created, LDK handles the rest. This is a large part of our API's goals - making it easier to integrate Lightning into existing on-chain wallets which have their own on-chain logic - without needing to move funds in and out of a separate Lightning wallet with on-chain transactions and a separate private key system.")]),e._v(" "),t("p",[e._v("LDK does not currently provide a sample wallet module, but its sample node implementation uses Bitcoin Core's wallet for UTXO management e.g. "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample/blob/2cd778e7acc959689e3b8462c529ffb3509aa1ec/src/main.rs#L245-L260",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1)])])}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/66.3a2e2b53.js b/assets/js/66.fe4a9b01.js similarity index 99% rename from assets/js/66.3a2e2b53.js rename to assets/js/66.fe4a9b01.js index 8b25986d8..7a6a32c68 100644 --- a/assets/js/66.3a2e2b53.js +++ b/assets/js/66.fe4a9b01.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[66],{437:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"key-management"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#key-management"}},[t._v("#")]),t._v(" Key Management")]),t._v(" "),s("p",[t._v("LDK provides a simple default "),s("code",[t._v("KeysManager")]),t._v(" implementation that takes a 32-byte seed for use as a BIP 32 extended key and derives keys from that. Check out the "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust docs"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("p",[t._v("However, LDK also allows to customize the way key material and entropy are sourced through custom implementations of the "),s("code",[t._v("NodeSigner")]),t._v(", "),s("code",[t._v("SignerProvider")]),t._v(", and "),s("code",[t._v("EntropySource")]),t._v(" traits located in "),s("code",[t._v("sign")]),t._v(". These traits include basic methods to provide public and private key material, as well as pseudorandom numbers.")]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("KeysManager")]),t._v(" can be constructed simply with only a 32-byte seed and some random integers which ensure uniqueness across restarts (defined as "),s("code",[t._v("starting_time_secs")]),t._v(" and "),s("code",[t._v("starting_time_nanos")]),t._v("):")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in random_32_bytes with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" random_32_bytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" start_time "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_interface_impl "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("sign"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("random_32_bytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" start_time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" start_time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in key_seed with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" key_seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n key_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in seed with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("repeating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" count"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("h1",{attrs:{id:"creating-a-unified-wallet"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-unified-wallet"}},[t._v("#")]),t._v(" Creating a Unified Wallet")]),t._v(" "),s("p",[t._v('LDK makes it simple to combine an on-chain and off-chain wallet in the same app. This means users don’t need to worry about storing two different recovery phrases. For apps containing a hierarchical deterministic wallet (or "HD Wallet") we recommend using the entropy from a '),s("a",{attrs:{href:"https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc#hardened-child-key-derivation",target:"_blank",rel:"noopener noreferrer"}},[t._v("hardened child key derivation"),s("OutboundLink")],1),t._v(" path for your LDK seed.")]),t._v(" "),s("p",[t._v("Using a "),s("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),s("OutboundLink")],1),t._v("-based wallet the steps would be as follows:")]),t._v(" "),s("ol",[s("li",[t._v("Generate a mnemonic/entropy source.")]),t._v(" "),s("li",[t._v("Build an HD wallet from that. That's now your on-chain wallet, and you can derive any BIP-compliant on-chain wallet/path for it from there.")]),t._v(" "),s("li",[t._v("Derive the private key at "),s("code",[t._v("m/535h")]),t._v(" (or some other custom path). That's 32 bytes and is your starting entropy for your LDK wallet.")]),t._v(" "),s("li",[t._v("Optional: use a custom "),s("code",[t._v("SignerProvider")]),t._v(" implementation to have the BDK wallet provide the destination and shutdown scripts (see "),s("a",{attrs:{href:"#spending-on-chain-funds"}},[t._v("Spending On-Chain Funds")]),t._v(").")])]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mnemonic")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("parse_in_normalized")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Language")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("English")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_seed_normalized")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Other supported networks include mainnet (Bitcoin), Regtest, Signet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" master_xprv "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ExtendedPrivKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_master")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" secp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Secp256k1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ExtendedPrivKey")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" master_xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ckd_priv")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("secp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChildNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Hardened")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" index"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("535")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldk_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("private_key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secret_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" cur "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("ldk_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" bip32RootKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DescriptorSecretKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TESTNET"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" password "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ldkDerivationPath "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DerivationPath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"m/535h"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DescriptorSecretKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bip32RootKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ldkDerivationPath"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token annotation builtin"}},[t._v("@OptIn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("kotlin"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ExperimentalUnsignedTypes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" entropy"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secretBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n entropy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mnemonic")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Other supported networks include mainnet (Bitcoin), Regtest, Signet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bip32RootKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DescriptorSecretKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("testnet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" password"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkDerivationPath "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DerivationPath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"m/535h"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkChild "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" bip32RootKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ldkDerivationPath"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkSeed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secretBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ldkSeed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Protection for on-chain wallet")]),t._v(" "),s("p",[t._v("An advantage to this approach is that the LDK entropy is contained within your initial mnemonic and a user only has one master private key to backup and secure. Another added benefit is that if your lightning keys were to be leaked we reduce the exposure to those funds and not the rest of the on-chain wallet.")])]),t._v(" "),s("h1",{attrs:{id:"spending-on-chain-funds"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spending-on-chain-funds"}},[t._v("#")]),t._v(" Spending On-Chain Funds")]),t._v(" "),s("p",[t._v("When a channel has been closed and some outputs on chain are spendable only by us, LDK provides a "),s("code",[t._v("util::events::Event::SpendableOutputs")]),t._v(" event in return from "),s("code",[t._v("ChannelMonitor::get_and_clear_pending_events()")]),t._v(". It contains a list of "),s("code",[t._v("sign::SpendableOutputDescriptor")]),t._v(" objects which describe the output and provide all necessary information to spend it.")]),t._v(" "),s("p",[t._v("If you're using "),s("code",[t._v("KeysManager")]),t._v(" directly, a utility method is provided which can generate a signed transaction given a list of "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects. "),s("code",[t._v("KeysManager::spend_spendable_outputs")]),t._v(" can be called any time after receiving the "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects to build a spending transaction, including delaying until sending funds to an external destination or opening a new channel. Note that if you open new channels directly with "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects, you must ensure all closing/destination scripts provided to LDK are SegWit (either native or P2SH-wrapped).")]),t._v(" "),s("p",[t._v("If you are not using "),s("code",[t._v("KeysManager")]),t._v(" for keys generation, you must re-derive the private keys yourself. Any "),s("code",[t._v("ChannelSigner")]),t._v(" object must provide a unique id via the "),s("code",[t._v("channel_keys_id")]),t._v(" function, whose value is provided back to you in the "),s("code",[t._v("SpendableOutputs")]),t._v(" objects. A "),s("code",[t._v("SpendableOutputDescriptor::StaticOutput")]),t._v(" element does not have this information as the output is sent to an output which used only "),s("code",[t._v("KeysInterface")]),t._v(" data, not per-channel data.")]),t._v(" "),s("p",[t._v("In order to make the outputs from channel closing spendable by a third-party wallet, a middleground between using the default "),s("code",[t._v("KeysManager")]),t._v(" and an entirely custom implementation of "),s("code",[t._v("SignerProvider")]),t._v("/"),s("code",[t._v("NodeSigner")]),t._v("/"),s("code",[t._v("EntropySource")]),t._v(" could be to implement a wrapper around "),s("code",[t._v("KeysManager")]),t._v(". Such a wrapper would need to override the respective methods returning the destination and shutdown scripts while simply dropping any instances of "),s("code",[t._v("SpendableOutputDescriptor::StaticOutput")]),t._v(", as these then could be spent by the third-party wallet from which the scripts had been derived.")]),t._v(" "),s("p",[t._v("For example, a wrapper based on BDK's "),s("a",{attrs:{href:"https://docs.rs/bdk/*/bdk/wallet/struct.Wallet.html",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("Wallet")]),s("OutboundLink")],1),t._v(" could look like this:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tinner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\twallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mutex")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_secs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_nanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mutex")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_secs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_nanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("C")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signing")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxOut")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tchange_destination_script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feerate_sat_per_1000_weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tlocktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PackedLockTime")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" secp_ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Secp256k1")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("C")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" only_non_static "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("descriptors\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("desc"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StaticOutput")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" desc "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("copied")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("collect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t\tonly_non_static"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\toutputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tchange_destination_script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tfeerate_sat_per_1000_weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tlocktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tsecp_ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignerProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("Signer")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InMemorySigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_destination_script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("lock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AddressIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("New")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to retrieve new address from wallet: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("script_pubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_shutdown_scriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("lock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AddressIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("New")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to retrieve new address from wallet: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payload "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bitcoin"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("util"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WitnessProgram")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" program "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_witness_program")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Invalid shutdown script: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t_ "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Tried to use a non-witness address. This must not ever happen."')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... and redirect all other trait method implementations to the `inner` `KeysManager`.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u128")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_keys_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signer")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_keys_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DecodeError")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NodeSigner")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... snip")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EntropySource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... snip")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("LDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeSecs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeNano"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("inner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" KeysManager\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Wallet\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" signerProvider"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LDKSignerProvider\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeNano"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet\n signerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("LDKSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldkkeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("TxOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Option_u32Z\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_TransactionNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" it "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StaticOutput "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTypedArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("inner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" LDKSignerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("SignerProviderInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LDKKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Boolean"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" UInt128"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" WriteableEcdsaChannelSigner "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_WriteableEcdsaChannelSignerDecodeErrorZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token annotation builtin"}},[t._v("@OptIn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExperimentalUnsignedTypes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_destination_script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_CVec_u8ZNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("AddressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("New"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" Result_CVec_u8ZNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Only applies to cooperative close transactions.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_shutdown_scriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_ShutdownScriptNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("AddressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("New"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" payload"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Payload "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WitnessProgram "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"V0"')])]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"V16"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("substring")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toIntOrNull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?:")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// Default to 0 if it doesn\'t match any "V0" to "V16"')]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ShutdownScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_witness_program")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WitnessVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Result_ShutdownScriptNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_ShutdownScriptInvalidShutdownScriptZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_ShutdownScriptInvalidShutdownScriptZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Result_ShutdownScriptNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyKeysManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet\n signerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxOut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_TransactionNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("filter "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" desc "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" desc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StaticOutput")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" locktime\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" res\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignerProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("weak")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getDestinationScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ScriptNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ScriptNoneZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("o"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getShutdownScriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ShutdownScriptNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payload "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("witnessProgram")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("`version`"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" `program`"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" payload "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("switch")]),t._v(" version "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v0"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v4"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v5"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v6"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v7"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v8"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v9"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v10"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v11"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v12"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v13"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v14"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v15"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v16"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("16")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newWitnessProgram")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ShutdownScriptNoneZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("o"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... and redirect all other trait method implementations to the `inner` `KeysManager`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("deriveChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WriteableEcdsaChannelSigner")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("deriveChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelKeysId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("generateChannelKeysId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bool")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generateChannelKeysId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userChannelId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("readChanSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_WriteableEcdsaChannelSignerDecodeErrorZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("readChanSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])})],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[66],{435:function(t,s,a){"use strict";a.r(s);var n=a(7),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"key-management"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#key-management"}},[t._v("#")]),t._v(" Key Management")]),t._v(" "),s("p",[t._v("LDK provides a simple default "),s("code",[t._v("KeysManager")]),t._v(" implementation that takes a 32-byte seed for use as a BIP 32 extended key and derives keys from that. Check out the "),s("a",{attrs:{href:"https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust docs"),s("OutboundLink")],1),t._v(".")]),t._v(" "),s("p",[t._v("However, LDK also allows to customize the way key material and entropy are sourced through custom implementations of the "),s("code",[t._v("NodeSigner")]),t._v(", "),s("code",[t._v("SignerProvider")]),t._v(", and "),s("code",[t._v("EntropySource")]),t._v(" traits located in "),s("code",[t._v("sign")]),t._v(". These traits include basic methods to provide public and private key material, as well as pseudorandom numbers.")]),t._v(" "),s("p",[t._v("A "),s("code",[t._v("KeysManager")]),t._v(" can be constructed simply with only a 32-byte seed and some random integers which ensure uniqueness across restarts (defined as "),s("code",[t._v("starting_time_secs")]),t._v(" and "),s("code",[t._v("starting_time_nanos")]),t._v("):")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in random_32_bytes with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("mut")]),t._v(" random_32_bytes "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" start_time "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_interface_impl "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("lightning"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("sign"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("random_32_bytes"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" start_time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" start_time"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in key_seed with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" key_seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n key_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Fill in seed with secure random data, or, on restart, reload the seed from disk.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("repeating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" count"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("h1",{attrs:{id:"creating-a-unified-wallet"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-unified-wallet"}},[t._v("#")]),t._v(" Creating a Unified Wallet")]),t._v(" "),s("p",[t._v('LDK makes it simple to combine an on-chain and off-chain wallet in the same app. This means users don’t need to worry about storing two different recovery phrases. For apps containing a hierarchical deterministic wallet (or "HD Wallet") we recommend using the entropy from a '),s("a",{attrs:{href:"https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc#hardened-child-key-derivation",target:"_blank",rel:"noopener noreferrer"}},[t._v("hardened child key derivation"),s("OutboundLink")],1),t._v(" path for your LDK seed.")]),t._v(" "),s("p",[t._v("Using a "),s("a",{attrs:{href:"https://bitcoindevkit.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("BDK"),s("OutboundLink")],1),t._v("-based wallet the steps would be as follows:")]),t._v(" "),s("ol",[s("li",[t._v("Generate a mnemonic/entropy source.")]),t._v(" "),s("li",[t._v("Build an HD wallet from that. That's now your on-chain wallet, and you can derive any BIP-compliant on-chain wallet/path for it from there.")]),t._v(" "),s("li",[t._v("Derive the private key at "),s("code",[t._v("m/535h")]),t._v(" (or some other custom path). That's 32 bytes and is your starting entropy for your LDK wallet.")]),t._v(" "),s("li",[t._v("Optional: use a custom "),s("code",[t._v("SignerProvider")]),t._v(" implementation to have the BDK wallet provide the destination and shutdown scripts (see "),s("a",{attrs:{href:"#spending-on-chain-funds"}},[t._v("Spending On-Chain Funds")]),t._v(").")])]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mnemonic")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("parse_in_normalized")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Language")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("English")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("to_seed_normalized")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Other supported networks include mainnet (Bitcoin), Regtest, Signet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" master_xprv "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ExtendedPrivKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_master")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Network")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Testnet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" secp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Secp256k1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ExtendedPrivKey")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" master_xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ckd_priv")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("secp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ChildNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Hardened")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" index"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("535")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldk_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" xprv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("private_key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secret_bytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" cur "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("now")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("duration_since")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SystemTime")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("UNIX_EPOCH")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keys_manager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("ldk_seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_secs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cur"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("subsec_nanos")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" bip32RootKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DescriptorSecretKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TESTNET"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" password "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ldkDerivationPath "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("DerivationPath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"m/535h"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" DescriptorSecretKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" bip32RootKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ldkDerivationPath"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token annotation builtin"}},[t._v("@OptIn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("kotlin"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ExperimentalUnsignedTypes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" entropy"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secretBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n entropy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("System"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("currentTimeMillis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toInt")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Use BDK to create and build the HD wallet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" mnemonic "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mnemonic")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fromString")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sock lyrics village put galaxy famous pass act ship second diagram pull"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Other supported networks include mainnet (Bitcoin), Regtest, Signet")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" bip32RootKey "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DescriptorSecretKey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("network"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("testnet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" mnemonic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" password"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token nil constant"}},[t._v("nil")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkDerivationPath "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DerivationPath")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"m/535h"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkChild "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" bip32RootKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ldkDerivationPath"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ldkSeed "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkChild"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("secretBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSDate")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeIntervalSince1970"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" timestampNanos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("truncating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NSNumber")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1000")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Seed the LDK KeysManager with the private key at m/535h")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" keysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ldkSeed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampSeconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\tstartingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" timestampNanos\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]},proxy:!0}])}),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Protection for on-chain wallet")]),t._v(" "),s("p",[t._v("An advantage to this approach is that the LDK entropy is contained within your initial mnemonic and a user only has one master private key to backup and secure. Another added benefit is that if your lightning keys were to be leaked we reduce the exposure to those funds and not the rest of the on-chain wallet.")])]),t._v(" "),s("h1",{attrs:{id:"spending-on-chain-funds"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#spending-on-chain-funds"}},[t._v("#")]),t._v(" Spending On-Chain Funds")]),t._v(" "),s("p",[t._v("When a channel has been closed and some outputs on chain are spendable only by us, LDK provides a "),s("code",[t._v("util::events::Event::SpendableOutputs")]),t._v(" event in return from "),s("code",[t._v("ChannelMonitor::get_and_clear_pending_events()")]),t._v(". It contains a list of "),s("code",[t._v("sign::SpendableOutputDescriptor")]),t._v(" objects which describe the output and provide all necessary information to spend it.")]),t._v(" "),s("p",[t._v("If you're using "),s("code",[t._v("KeysManager")]),t._v(" directly, a utility method is provided which can generate a signed transaction given a list of "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects. "),s("code",[t._v("KeysManager::spend_spendable_outputs")]),t._v(" can be called any time after receiving the "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects to build a spending transaction, including delaying until sending funds to an external destination or opening a new channel. Note that if you open new channels directly with "),s("code",[t._v("SpendableOutputDescriptor")]),t._v(" objects, you must ensure all closing/destination scripts provided to LDK are SegWit (either native or P2SH-wrapped).")]),t._v(" "),s("p",[t._v("If you are not using "),s("code",[t._v("KeysManager")]),t._v(" for keys generation, you must re-derive the private keys yourself. Any "),s("code",[t._v("ChannelSigner")]),t._v(" object must provide a unique id via the "),s("code",[t._v("channel_keys_id")]),t._v(" function, whose value is provided back to you in the "),s("code",[t._v("SpendableOutputs")]),t._v(" objects. A "),s("code",[t._v("SpendableOutputDescriptor::StaticOutput")]),t._v(" element does not have this information as the output is sent to an output which used only "),s("code",[t._v("KeysInterface")]),t._v(" data, not per-channel data.")]),t._v(" "),s("p",[t._v("In order to make the outputs from channel closing spendable by a third-party wallet, a middleground between using the default "),s("code",[t._v("KeysManager")]),t._v(" and an entirely custom implementation of "),s("code",[t._v("SignerProvider")]),t._v("/"),s("code",[t._v("NodeSigner")]),t._v("/"),s("code",[t._v("EntropySource")]),t._v(" could be to implement a wrapper around "),s("code",[t._v("KeysManager")]),t._v(". Such a wrapper would need to override the respective methods returning the destination and shutdown scripts while simply dropping any instances of "),s("code",[t._v("SpendableOutputDescriptor::StaticOutput")]),t._v(", as these then could be spent by the third-party wallet from which the scripts had been derived.")]),t._v(" "),s("p",[t._v("For example, a wrapper based on BDK's "),s("a",{attrs:{href:"https://docs.rs/bdk/*/bdk/wallet/struct.Wallet.html",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("Wallet")]),s("OutboundLink")],1),t._v(" could look like this:")]),t._v(" "),s("CodeSwitcher",{attrs:{languages:{rust:"Rust",kotlin:"Kotlin",swift:"Swift"}},scopedSlots:t._u([{key:"rust",fn:function(){return[s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-rust"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("struct")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\tinner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\twallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mutex")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\tseed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_secs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_nanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arc")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mutex")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_secs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" starting_time_nanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pub")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("C")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signing")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxOut")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tchange_destination_script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feerate_sat_per_1000_weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\tlocktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Option")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PackedLockTime")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" secp_ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Secp256k1")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("C")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Transaction")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" only_non_static "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("descriptors\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("iter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("filter")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("desc"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StaticOutput")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" desc "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("copied")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("collect")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Vec")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t\tonly_non_static"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\toutputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tchange_destination_script"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tfeerate_sat_per_1000_weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tlocktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t\tsecp_ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignerProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token type-definition class-name"}},[t._v("Signer")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("InMemorySigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_destination_script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("lock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AddressIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("New")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to retrieve new address from wallet: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("script_pubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("get_shutdown_scriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("lock")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unwrap")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("AddressIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("New")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Failed to retrieve new address from wallet: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("match")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("payload "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bitcoin"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("util"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WitnessProgram")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" program "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_witness_program")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("map_err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token closure-params"}},[s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")]),t._v("e"),s("span",{pre:!0,attrs:{class:"token closure-punctuation punctuation"}},[t._v("|")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("eprintln!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Invalid shutdown script: {:?}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" e"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\t\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t\t\t_ "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=>")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token macro property"}},[t._v("panic!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Tried to use a non-witness address. This must not ever happen."')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... and redirect all other trait method implementations to the `inner` `KeysManager`.")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("bool")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u128")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_channel_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_keys_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signer")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channel_value_satoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channel_keys_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fn")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("u8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("Self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DecodeError")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NodeSigner")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... snip")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("impl")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("EntropySource")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("where")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("D")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("bdk"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")]),t._v("database"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("::")])]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BatchDatabase")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... snip")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"kotlin",fn:function(){return[s("div",{staticClass:"language-kotlin extra-class"},[s("pre",{pre:!0,attrs:{class:"language-kotlin"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("LDKKeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeSecs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeNano"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("inner")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" KeysManager\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Wallet\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" signerProvider"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LDKSignerProvider\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" KeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("of")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startTimeNano"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet\n signerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("LDKSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("ldkkeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("TxOut"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Int"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Option_u32Z\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_TransactionNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Array"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("filter")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" it "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" SpendableOutputDescriptor"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("StaticOutput "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toTypedArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("inner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spend_spendable_outputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" LDKSignerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" SignerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("SignerProviderInterface")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" LDKKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Boolean"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" UInt128"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generate_channel_keys_id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Long"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" WriteableEcdsaChannelSigner "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("derive_channel_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ByteArray"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_WriteableEcdsaChannelSignerDecodeErrorZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("as_SignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("read_chan_signer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token annotation builtin"}},[t._v("@OptIn")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExperimentalUnsignedTypes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("::")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_destination_script")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_CVec_u8ZNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("AddressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("New"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" Result_CVec_u8ZNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Only applies to cooperative close transactions.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fun")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("get_shutdown_scriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Result_ShutdownScriptNoneZ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ldkkeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("AddressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("New"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" payload"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Payload "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" Payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("WitnessProgram "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("when")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"V0"')])]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("..")]),s("span",{pre:!0,attrs:{class:"token string-literal singleline"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"V16"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("substring")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toIntOrNull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?:")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// Default to 0 if it doesn\'t match any "V0" to "V16"')]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ShutdownScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("new_witness_program")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("WitnessVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByte")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n payload"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toByteArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n Result_ShutdownScriptNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ok")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" Result_ShutdownScriptInvalidShutdownScriptZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Result_ShutdownScriptInvalidShutdownScriptZ_OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Result_ShutdownScriptNoneZ"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("err")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]},proxy:!0},{key:"swift",fn:function(){return[s("div",{staticClass:"language-swift extra-class"},[s("pre",{pre:!0,attrs:{class:"language-swift"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyKeysManager")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("init")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BitcoinDevKit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Wallet")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("KeysManager")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" seed"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" startingTimeSecs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" startingTimeNanos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" wallet\n signerProvider "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n signerProvider"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("myKeysManager "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We drop all occurences of `SpendableOutputDescriptor::StaticOutput` (since they will be")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// spendable by the BDK wallet) and forward any other descriptors to")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// `KeysManager::spend_spendable_outputs`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Note you should set `locktime` to the current block height to mitigate fee sniping.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// See https://bitcoinops.org/en/topics/fee-sniping/ for more information.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TxOut")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt32")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_TransactionNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SpendableOutputDescriptor")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("filter "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" desc "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" desc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValueType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("StaticOutput")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("self")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("spendSpendableOutputs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n descriptors"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" onlyNonStatic"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" outputs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" changeDestinationScript"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" feerateSatPer1000Weight"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n locktime"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" locktime\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" res\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MySignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SignerProvider")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("weak")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyKeysManager")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We return the destination and shutdown scripts derived by the BDK wallet.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getDestinationScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ScriptNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ScriptNoneZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("o"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("scriptPubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("toBytes")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("getShutdownScriptpubkey")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ShutdownScriptNoneZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wallet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getAddress")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addressIndex"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("address\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" payload "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("payload")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("witnessProgram")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("`version`"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" `program`"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" payload "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("switch")]),t._v(" version "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v0"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v4"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v5"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v6"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v7"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("7")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v8"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v9"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v10"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v11"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v12"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v13"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v14"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v15"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("v16"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n ver "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("16")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" res "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ShutdownScript")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("newWitnessProgram")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("version"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" program"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_ShutdownScriptNoneZ")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithOk")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("o"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" res"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getValue")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("initWithErr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... and redirect all other trait method implementations to the `inner` `KeysManager`.")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("deriveChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WriteableEcdsaChannelSigner")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("deriveChannelSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelKeysId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelKeysId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("generateChannelKeysId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bool")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt64")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("generateChannelKeysId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" inbound"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" channelValueSatoshis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n userChannelId"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" userChannelId\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function-definition function"}},[t._v("readChanSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UInt8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("->")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Bindings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Result_WriteableEcdsaChannelSignerDecodeErrorZ")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" myKeysManager"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inner"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("asSignerProvider")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("readChanSigner")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" reader"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]},proxy:!0}])})],1)}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/67.909115b4.js b/assets/js/67.59d24835.js similarity index 88% rename from assets/js/67.909115b4.js rename to assets/js/67.59d24835.js index 1dfa34d5f..66cdc01f7 100644 --- a/assets/js/67.909115b4.js +++ b/assets/js/67.59d24835.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[67],{440:function(t,s,n){"use strict";n.r(s);var a=n(7),i=Object(a.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"language-bindings"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#language-bindings"}},[this._v("#")]),this._v(" Language Bindings")]),this._v(" "),t("p",[this._v("TODO")]),this._v(" "),t("p",[this._v("state of language bindings on a per-language basis")])])}),[],!1,null,null,null);s.default=i.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[67],{436:function(t,s,n){"use strict";n.r(s);var a=n(7),i=Object(a.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"language-bindings"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#language-bindings"}},[this._v("#")]),this._v(" Language Bindings")]),this._v(" "),t("p",[this._v("TODO")]),this._v(" "),t("p",[this._v("state of language bindings on a per-language basis")])])}),[],!1,null,null,null);s.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/68.f08885aa.js b/assets/js/68.81f20861.js similarity index 86% rename from assets/js/68.f08885aa.js rename to assets/js/68.81f20861.js index 3c032d4ae..51f4114f7 100644 --- a/assets/js/68.f08885aa.js +++ b/assets/js/68.81f20861.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[68],{438:function(t,s,e){"use strict";e.r(s);var a=e(7),n=Object(a.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"data-persistence"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#data-persistence"}},[this._v("#")]),this._v(" Data Persistence")]),this._v(" "),t("p",[this._v("TODO")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[68],{437:function(t,s,e){"use strict";e.r(s);var a=e(7),n=Object(a.a)({},(function(){var t=this._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[t("h1",{attrs:{id:"data-persistence"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#data-persistence"}},[this._v("#")]),this._v(" Data Persistence")]),this._v(" "),t("p",[this._v("TODO")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/69.48f3811e.js b/assets/js/69.8b5e4171.js similarity index 99% rename from assets/js/69.48f3811e.js rename to assets/js/69.8b5e4171.js index a07e653bc..5239c6d29 100644 --- a/assets/js/69.48f3811e.js +++ b/assets/js/69.8b5e4171.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[69],{439:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"running-a-sample-ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#running-a-sample-ldk-node"}},[e._v("#")]),e._v(" Running a sample LDK node")]),e._v(" "),t("p",[e._v("Let's run our first LDK node. We'll ensure we have a compatible Rust toolchain installed, setup Polar to create a local Lightning network and then start running the node.")]),e._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[e._v("Not recommended for production use!")]),e._v(" "),t("p",[e._v("This guide is a quick start to get you up and running with an LDK node. It serves as a playground and a foundation to build upon and is NOT recommended for production environments. LDK doesn't come with a pre-packaged node but gives you the tools to build a node from scratch!")])]),e._v(" "),t("h2",{attrs:{id:"installing-rust"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#installing-rust"}},[e._v("#")]),e._v(" Installing Rust")]),e._v(" "),t("p",[e._v("If you already have a working installation of the latest Rust compiler, feel free to skip to the next section.")]),e._v(" "),t("p",[e._v("To install the latest version of Rust, we recommend using "),t("code",[e._v("rustup")]),e._v(". Install "),t("code",[e._v("rustup")]),e._v(" by following the instructions on "),t("a",{attrs:{href:"https://rustup.rs/",target:"_blank",rel:"noopener noreferrer"}},[e._v("its website"),t("OutboundLink")],1),e._v(". Once "),t("code",[e._v("rustup")]),e._v(" is installed, ensure the latest toolchain is installed by running the command:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("rustup default stable\n")])])]),t("h2",{attrs:{id:"setup-polar"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#setup-polar"}},[e._v("#")]),e._v(" Setup Polar")]),e._v(" "),t("p",[e._v("Next, let's setup Polar, which was built to help Lightning Network application developers quickly spin up one or more networks locally on their computers in regtest mode.")]),e._v(" "),t("p",[e._v("Polar can be "),t("a",{attrs:{href:"https://lightningpolar.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("downloaded"),t("OutboundLink")],1),e._v(" for MacOS, Linux, and Windows. The source code is hosted "),t("a",{attrs:{href:"https://github.com/jamaljsr/polar/releases/",target:"_blank",rel:"noopener noreferrer"}},[e._v("on Github"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("Mac and Windows users will need to install "),t("a",{attrs:{href:"https://www.docker.com/products/docker-desktop",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Desktop"),t("OutboundLink")],1),e._v(" as a dependency before using Polar. Linux users will need to download both "),t("a",{attrs:{href:"https://docs.docker.com/get-docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Server"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://docs.docker.com/compose/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Compose"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("After downloading, installing, and running Polar, spin up a new cluster of LND, Core Lightning, eclair, and bitcoind nodes. This will create a Docker container within which Polar will operate.")]),e._v(" "),t("p",[e._v("Click the orange "),t("strong",[e._v("Create Network")]),e._v(" button and Polar should display a new interface.")]),e._v(" "),t("p",[e._v("Press the orange "),t("strong",[e._v("Start")]),e._v(" button in the top right corner to start your local network. It takes a couple seconds for the nodes to boot up, but the indicator lights will eventually turn green signaling that the process has completed.")]),e._v(" "),t("h2",{attrs:{id:"running-the-ldk-sample-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#running-the-ldk-sample-node"}},[e._v("#")]),e._v(" Running the LDK Sample Node")]),e._v(" "),t("p",[e._v("Start by cloning the LDK sample node from Github and changing into the new directory")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("git clone https://github.com/lightningdevkit/ldk-sample\ncd ldk-sample\n")])])]),t("p",[e._v("Now, run the following command:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("cargo run polaruser:polarpass@127.0.0.1:18443 ./ 9732 regtest hellolightning 0.0.0.0:9732\n")])])]),t("p",[e._v("If you have a different setup that doesn't involve Polar you can modify this command so that it contains different credentials.")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("cargo run :@: [] [] [] []\n")])])]),t("p",[t("code",[e._v("bitcoind")]),e._v("'s RPC username and password likely can be found through "),t("code",[e._v("cat ~/.bitcoin/.cookie")]),e._v(".")]),e._v(" "),t("p",[t("code",[e._v("bitcoin-network")]),e._v(": defaults to "),t("code",[e._v("testnet")]),e._v(". Options: "),t("code",[e._v("testnet")]),e._v(", "),t("code",[e._v("regtest")]),e._v(", and "),t("code",[e._v("signet")]),e._v(".")]),e._v(" "),t("p",[t("code",[e._v("ldk-peer-listening-port")]),e._v(": defaults to 9735.")]),e._v(" "),t("p",[t("code",[e._v("announced-node-name")]),e._v(" and "),t("code",[e._v("announced-listen-addr")]),e._v(" : default to nothing, disabling any public announcements of this node.")]),e._v(" "),t("p",[t("code",[e._v("announced-node-name")]),e._v(": can be any string up to 32 bytes in length, representing this node's alias.\n"),t("code",[e._v("announced-listen-addr")]),e._v(": can be set to an IPv4 or IPv6 address to announce that as a publicly-connectable address for this node.")]),e._v(" "),t("p",[e._v("Your LDK node should now be in action!")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v('LDK startup successful. To view available commands: "help".\nLDK logs are available at /.ldk/logs\nLocal Node ID is 02e8788eb41ac1731352d87ced719afce91a1201cf0d6cca12ee79502db1b0e317.\n')])])]),t("p",[e._v("If you want to connect to another node you created with Polar select the node there. In the "),t("strong",[e._v("Connect")]),e._v(" tab you can copy the "),t("code",[e._v("P2P External")]),e._v(" connection info. Running "),t("code",[e._v("connectpeer")]),e._v(" with that will get you connected.")]),e._v(" "),t("p",[e._v("To check out the complete reference for constructing a Lightning node with LDK check out the "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("Github repo"),t("OutboundLink")],1)])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[69],{438:function(e,t,n){"use strict";n.r(t);var o=n(7),a=Object(o.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"running-a-sample-ldk-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#running-a-sample-ldk-node"}},[e._v("#")]),e._v(" Running a sample LDK node")]),e._v(" "),t("p",[e._v("Let's run our first LDK node. We'll ensure we have a compatible Rust toolchain installed, setup Polar to create a local Lightning network and then start running the node.")]),e._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[e._v("Not recommended for production use!")]),e._v(" "),t("p",[e._v("This guide is a quick start to get you up and running with an LDK node. It serves as a playground and a foundation to build upon and is NOT recommended for production environments. LDK doesn't come with a pre-packaged node but gives you the tools to build a node from scratch!")])]),e._v(" "),t("h2",{attrs:{id:"installing-rust"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#installing-rust"}},[e._v("#")]),e._v(" Installing Rust")]),e._v(" "),t("p",[e._v("If you already have a working installation of the latest Rust compiler, feel free to skip to the next section.")]),e._v(" "),t("p",[e._v("To install the latest version of Rust, we recommend using "),t("code",[e._v("rustup")]),e._v(". Install "),t("code",[e._v("rustup")]),e._v(" by following the instructions on "),t("a",{attrs:{href:"https://rustup.rs/",target:"_blank",rel:"noopener noreferrer"}},[e._v("its website"),t("OutboundLink")],1),e._v(". Once "),t("code",[e._v("rustup")]),e._v(" is installed, ensure the latest toolchain is installed by running the command:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("rustup default stable\n")])])]),t("h2",{attrs:{id:"setup-polar"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#setup-polar"}},[e._v("#")]),e._v(" Setup Polar")]),e._v(" "),t("p",[e._v("Next, let's setup Polar, which was built to help Lightning Network application developers quickly spin up one or more networks locally on their computers in regtest mode.")]),e._v(" "),t("p",[e._v("Polar can be "),t("a",{attrs:{href:"https://lightningpolar.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("downloaded"),t("OutboundLink")],1),e._v(" for MacOS, Linux, and Windows. The source code is hosted "),t("a",{attrs:{href:"https://github.com/jamaljsr/polar/releases/",target:"_blank",rel:"noopener noreferrer"}},[e._v("on Github"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("Mac and Windows users will need to install "),t("a",{attrs:{href:"https://www.docker.com/products/docker-desktop",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Desktop"),t("OutboundLink")],1),e._v(" as a dependency before using Polar. Linux users will need to download both "),t("a",{attrs:{href:"https://docs.docker.com/get-docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Server"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://docs.docker.com/compose/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Compose"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("After downloading, installing, and running Polar, spin up a new cluster of LND, Core Lightning, eclair, and bitcoind nodes. This will create a Docker container within which Polar will operate.")]),e._v(" "),t("p",[e._v("Click the orange "),t("strong",[e._v("Create Network")]),e._v(" button and Polar should display a new interface.")]),e._v(" "),t("p",[e._v("Press the orange "),t("strong",[e._v("Start")]),e._v(" button in the top right corner to start your local network. It takes a couple seconds for the nodes to boot up, but the indicator lights will eventually turn green signaling that the process has completed.")]),e._v(" "),t("h2",{attrs:{id:"running-the-ldk-sample-node"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#running-the-ldk-sample-node"}},[e._v("#")]),e._v(" Running the LDK Sample Node")]),e._v(" "),t("p",[e._v("Start by cloning the LDK sample node from Github and changing into the new directory")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("git clone https://github.com/lightningdevkit/ldk-sample\ncd ldk-sample\n")])])]),t("p",[e._v("Now, run the following command:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("cargo run polaruser:polarpass@127.0.0.1:18443 ./ 9732 regtest hellolightning 0.0.0.0:9732\n")])])]),t("p",[e._v("If you have a different setup that doesn't involve Polar you can modify this command so that it contains different credentials.")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("cargo run :@: [] [] [] []\n")])])]),t("p",[t("code",[e._v("bitcoind")]),e._v("'s RPC username and password likely can be found through "),t("code",[e._v("cat ~/.bitcoin/.cookie")]),e._v(".")]),e._v(" "),t("p",[t("code",[e._v("bitcoin-network")]),e._v(": defaults to "),t("code",[e._v("testnet")]),e._v(". Options: "),t("code",[e._v("testnet")]),e._v(", "),t("code",[e._v("regtest")]),e._v(", and "),t("code",[e._v("signet")]),e._v(".")]),e._v(" "),t("p",[t("code",[e._v("ldk-peer-listening-port")]),e._v(": defaults to 9735.")]),e._v(" "),t("p",[t("code",[e._v("announced-node-name")]),e._v(" and "),t("code",[e._v("announced-listen-addr")]),e._v(" : default to nothing, disabling any public announcements of this node.")]),e._v(" "),t("p",[t("code",[e._v("announced-node-name")]),e._v(": can be any string up to 32 bytes in length, representing this node's alias.\n"),t("code",[e._v("announced-listen-addr")]),e._v(": can be set to an IPv4 or IPv6 address to announce that as a publicly-connectable address for this node.")]),e._v(" "),t("p",[e._v("Your LDK node should now be in action!")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v('LDK startup successful. To view available commands: "help".\nLDK logs are available at /.ldk/logs\nLocal Node ID is 02e8788eb41ac1731352d87ced719afce91a1201cf0d6cca12ee79502db1b0e317.\n')])])]),t("p",[e._v("If you want to connect to another node you created with Polar select the node there. In the "),t("strong",[e._v("Connect")]),e._v(" tab you can copy the "),t("code",[e._v("P2P External")]),e._v(" connection info. Running "),t("code",[e._v("connectpeer")]),e._v(" with that will get you connected.")]),e._v(" "),t("p",[e._v("To check out the complete reference for constructing a Lightning node with LDK check out the "),t("a",{attrs:{href:"https://github.com/lightningdevkit/ldk-sample",target:"_blank",rel:"noopener noreferrer"}},[e._v("Github repo"),t("OutboundLink")],1)])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/7.e114aea2.js b/assets/js/7.e114aea2.js new file mode 100644 index 000000000..cebf7fb2b --- /dev/null +++ b/assets/js/7.e114aea2.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{253:function(A,t){A.exports="data:image/png;base64,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"},280:function(A,t,g){A.exports=g.p+"assets/img/alby.d8538ae1.svg"},281:function(A,t){A.exports="data:image/png;base64,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"},287:function(A,t){A.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAACCCAYAAACKAxD9AAAABGdBTUEAALGPC/xhBQAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAIKgAwAEAAAAAQAAAIIAAAAAFUiq0wAAAAlwSFlzAAALEwAACxMBAJqcGAAAAgRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjUxMjwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj41MTI8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KpWOcfAAAGVxJREFUeAHtXQmQXMV5/t8ce42WwyABEtiEREbIRVUobGOwy6wqNlVQgBOkFZgjTiRYsAkxxsaGGNBiDMHGUJjCBnRhSMwhcSQWiStOJSzYiXEcpVwOtwJCHBIgDiHtjHZ3js73/e/17s7u3PNmdt7s6619M++9fv26//767//qHpEwhRQIKRBSIKRASIGQAiEFQgqEFAgpEFIgpEBIgZACIQVCCoQUCCkQUiCkQEiBkAIhBWqngFP7o238pDGODElUnpCctvJEiej3Qcc9b+Omh02zFNhgovbrtM9S96ZlDtaFWLCq2+DasqOXO1m5xxwgY3IJ3vZpcfTvNzjeins7xeZpcFWaXXw4NViK2w6+2xyNCeHfJCFzJePdjONzWN6VrHxOBpzftSMYQiCwrykTOI5BB3fIbnlBuuVw2SsjuEMI4D4g0S2duPYGjkfKnzvJ8Wc0Q/APkeA3wYcWrBZ3itwjV8kcBcEoSu3CP+WFKKaFTsBiVHplAaaMv9I32mf0JPiHkCMMmohQG1hvjsCU8Dw6PQ4OYNC1U2mTA1wi4A3bZD64winOaDtxhZAjCDqXycj3pQcgyKlkMBUEzBGRNO71yEcwQZzNC6pi6pfgH2Y3EAZNDNwgI3ebz0uHLJUUxEHHmyYK9S01iCxuODKgt62doVDegF0rhPyANaHW6kJAFAiITGvM7yEFHI35n91c3I6gmcEz4uAOWaiWK5z/bBcNYvZyhLu8kb/WfBUCIkGQrgAEnEIIBMHR5QrPTpMlXLgE7Dg7OcKEgDgXHboF43tffBYSEAt1p0F+B/mT4CIL5Txnh9jyCuUOyLXZyRHoO2Ay8l0YjggCcoNKBwXlhAyeS0ChPE/LOaTsdKLZWvlQaeNbuQ3V1c1aENeZjwMOv0WnVsoJJr/HlRPSMD6tlKPUGCWTZI7JOQPyffZxhGe148kNbta5XlRArLa7qEpmYXI6UtbJqfrwYLC5wuwCwuOqLuZknTkH9oDPwmRMb0KtjjfjTSYXKhAWewCrFlItkn/2TA0T/oRu+BNeRPcfChgwvqC2weCg4wkFfkZksfyl83yQhcbaiNAiKK6qGtY3sFuuhphHEFBArL39Lj9Ig7NQeFypdbFCaFUVa43Ms4MjWAHxbrMQnfYcui6q47lyTaFYb+VQEo1Lb0KDWCgXO8NB9T/UPiKKkaaVr2flJozgKCYEygZ+DAI6oeh/OBiC4zJt+lAwhcb2BwL9CYw6WmdOhgHoC2X9CdUC2fofTLD9D36MimpJ18T8k3T7teYZOJYWV+hPqLaOros6KyfISufXQfQ/tDdHsP6EdeYyCIgEQWX+hGphQP9DBx6yXCGA/of25QjW/r/GHARpgP6EXnRXLVbESmBh/Q/DkBAWQpV8M2iqZPtyBKvKOXIDuAFBUI0/oZLOn5yHTqg03jMHoqPrf7Dvn5yrhb+3J0ew6uJ6cxw4wVPonEZxgomudacHahHPw6qw2I11mCSjTORsyW/tyRGsPyErt3gG5MavUHIAOfofOmWRrJVTtLcD5H9oPyDcZeIajLrWfAms+gTPn1Au6sivUeraG41cpAUGyP/QXlOD9SfcaxLQELaAGxwCVl27P6FaeFj/A+OXHEwPK50XgiI0thdHsP6EMbkG3IAgqM+fUC0QrP8hgWnCyAp9PCBCY/twBCsg3mUWQYV7Fp3AtjVeSJwOFut/2AHbwsKgrIpqL47ATonBn9ANEHCZmj/+hOldXfqK9T8cgunJ9T9c2/r+h/YAAgNO6E9Yb06F1H4qBMTS6xNKd2T9d63/wa5/oMzQ4snHqQE686CyY/+aPEjW7q09KFqqp6tTUFyPKSEG9Y1qXPn1CUVL9OmG639Iy/FygfOUDD6OxTRL7Ppqn17hXzG1hmlN1ICm3CEIR0NYMaQdN3HLl2/9G6KycTk7tnCiP+FCdP06uRwC4iIEmVNAdFcxF36iOVetgSmrXsmnZHGfkT6AQfoE9EJ7ygG8OdW0b6mPI/RjY4mNYMlMJ5tO2XfvPMmOxSTaSSGtjoQV6WknIh2R3XL/Pu8ULcj6E9aZ+eAdLwKOCTDhmRAQC1XR+h/2yI7RT8jVXS/kZerDdNZCgKidI1gQfHH3gZKODoqkTpOMmQdpzZGMHcDFBHfbV4U+SS4M6AhGTBrcZtnwNfLQnO9JIc7gqmbs+hsQHJJArEFrcAO3x+l/MOBXvTLibJZT9myV3ujvJZP7uWTTj8k/OLs0mwIC3HSGU20cwYKgfxS2s/SQdCbmShp9YHxsj4F8FemEmDVGbH1YHuh5Lc84Y9XF9eYEyOT/AQg0z3BUTafRopCC7PQkqhf1ZPN08l1cWSMdo38rPz1gt7QAGGrQGiCUcTrgVGAymyQOEIwmR9FhwH8Okb0+/VPSNhzg5gMZzXLjCqRr3Q8e+7XjmetmTAlMdU5HWob/B+ovCdTtYNBneBiBbcmMOLEDQLcrZLRzi/QnT3flK3A/XSTjfxUqKbF6IPR5OnFP6nzp6DlC0il2Eoaudgc5jF//WYl3U6a6XR7tfVtHzeCgq4bRn8CtbtaaFZgSPoXdTMiKmuVPwKuqTo4cGiOtORXHJJcxMpYak0jHPIn1/KMsS16l/pFB0o5aUPNT9TLCXG/kOfJ591uJ7ehqb08O00IcnOY16X3nu1qMClb45voToCWYXrz/BkQPE3rVA7r2ulX3JLuVItP+IPVcVPM9MC7AGO3oABfN6tTXmbgOnIHOslWqWQwpsKt7T525qyfgxzwgSO6AcUjUWYkCj8NMC8JFI9+Sn/zBiHIDq25Zf4LIKrDcg0Bkzh/Vt6PASxt2iZMWFdoP45DGycSYJxeLyGgqI/Gea2Tp8LkyBFsDZYYmp+oJ+IxthrPd++b33JyRWCIm6eQTsqHnfhUQaaNgooB4oZOGBZEO3q/DZsDUdKLpW6s5WK4wD1WdgxOrVLll4ALkgzRUZsdZLWekDp2QGap5SX15qwfCTguE6M/qe3XRp7HuAPzecb6uOcaBNyl/Tv0JoN+M+RMmVabCr5RuutHnhwEMoxg7+ZSPiMmmIXN1SzR3g5Y4NCVHha+pNVt+dSopxc7V73Q9KGPDL8F4xBHpCnGVPF86D4iRgP6dvUs2JjYri7QGq0GwS3d9wulYTHLKjPsTSrej+N0FIBcpNp2PxmUsyXnjPFm652PN5grVA4FztdV7I9FbdS4Xz7pYvPnl7+iS0hiJsUvi2av0gT4LMEjS3PSKlkQDbpDPWsuX3Qo57PSwD8SCg/E/xj6fVjFoSj0T3LCJXKEGIKDyliuMdK9Hx22XSJyiUH1cAfZIiUMLNZFValYe8ELOSCu7PmGBfBMC4kchHlJAbGV1kbWensgFSPHDQC6CeToQolArCYRzZemuI5rJFWoDArnCwH/HZZODWsvtgoGMVM84zUq0h9zgf+XhnttYmKz2VChyAQqI9Cc4WMm8V++SuQYvseNpdj4wZmQ/kJ4icD4YeJYGV4CCGfuqNrBJXKFGIKCKq491JfmOxJ3owPdQcaJh+synrang4ChFvqE5VX0C2Nzk1tHIjTAe9YCQ5Ab55PMytvgH28PAem7o60BozEBodIPb8ioOWYgahCAo/ozkIc3iCrUDwXKF+5z30S93Klt3MZ7XrApOMCUkopIZfgTOpV8I/RiT1UXKBuvMZ6CHnwebPacfZT8VlNtKWQgCBzCOAQjciisjf9gRk+4I91awgLf1hbEpR6E5AQ3iYr24fXPDp8E6gIAqzj/WnQ5i8iOYmpPiRKrlCiCCQ5tBRqLZb2qjxw1WOLP+BJEfeMrUVKLpIy1+cEFAHjacWyV7RhfJ+5BzHLlSDkH/ZsAKGViXl8gVoEIb5yI5e9f+svrj4IKNNT3XBwRuZk02/kBiO5qyXn0D4hl/8hpW5ISjowNSspgb5cH9XpI8AdHzJ6wzKxGDeFwA/AmFG8k2wmWC9NcyEP2OXNb1f3K5sxWh7jdikrtIutF+BrHkJ0CDdoUEfkAkNqC3BjY3VC6qf66lMEdALB05Ahh4QUc4DOmofLmy4U/ogDo49pqM7F4km+ZD8CTqIRvY9QmuP2EL9AOakkms+oCbT+xmnHHlUxT+kN/I+c6n1DJq30qbiGzF9hpzt0LrOlhy6antc+mTG3tDnMRCeHwhJnv0sWX4+Fk/YS1XeLjrZXTi37kjHN1WPiGmDzOJkYcUBNRCCAKmCX/CYGD8CYXby+AUwvey8dsEwHKPAwwcTvojR8ExE4FDKgOusEBywyv0eev5HS/Mvy/1A4F1mbvR7cBo7hbICrxSARvzOt2o/5DyBiZMGo7glaO6uMYcBZBcFhh/Aludn7jRFtdD3qObd1vLKPPYDt2VOgl+lfnqhSzM7bA/E8aUI5dOCNGNkRX8AQKDSxmY+WDv0zrC4wk211Uv+a1ggnaQQZa4sxyd34XphV4Xg0+EJGm6U39DxS2n4JApWGxrXGS8YhxaThK88UqvSuQNSOhIakWcUnOQjRiJVZgjMDOAMAKtas4fiUmewwvjINIT/w7+AIH1mdvncgXHgQmYQm5Zyx/kg9GsZBHckk0/ifnzk3Lje/vKj82Rcpd5FALWZz0BsQLu4h9BfCqJvwHF/r0W3G0H2uMuzGXhAx63fDp5Odj+kZLdS2KVUg8xvShpXSccQdSA5O9Is7GMy5L/DOvYyZgmUGloFcUS387fSDgUdoRP4HtW3gaA5iknGFE5oxSBipU609ehCWEQpLFPwgoshGUklRXyrGB9VnI+An23iBPtgXbAXi7TD+j8eA9UyuGl8lDvI6qp+QwI/zjCZPJHIje5KAb7K5VIAkrV24az8laWG13PAxAEnIDCZhBB4LaWrTbyDQUBZQMrBA+B1TNlMSV0JAACGI7KgoAPYDohXSTiWV49YZOXfEqlO6ral9BlTNRv6H5csqlfQhBi+aU1CDYwir9XxihY0eTqXqn23a2Q3/1ZwCiAvAnq4j+pujjosXLKUBzF/Xs/I5Gu82CWh3CAKaOyBHkqmUV84/EI7z9J1XVdLFPZw5Xk8hcIfKNFfQSyQiWJ3d4BzrgdeNmV5Z6o0+xslRTTAnkI4hicYtwb4fJp9RnqcweEyd2MKYG3dYxPy1fugi177s7ani9SfgOAwBEAVrYhsUkyqc1AMVtdmiuwchSet6mQybMgJv6YB9NNukEGBUQ1GuGKtZEsSzLy+5Ma0l791EeuACNT1+fkjN2f1mWAlMl8Sv4DgRWzerIxQL/KQaXRy7udyPca8LIHiGDzSj/Bt7RS4oLXOJTF7bCBfkcrNmDVZwwK+gr6oRGJuUEyqh3XSncAAcSJRl1ZwUcK1Fqh0lUY8jjAw4kHIOk+L9Fuag4c88UTa8II31fBFcrI0MULmaE7ExtuXimnIUaDy/RVW0B9rI/AdAxCQMRvSHFJmCc0Vl9dOuhApMifSv/wH+tCI5+4QmOAQCmZzih+RiK3eEu9SgOBd7uAgG2YWShHBYcr0GYQg/HoV1j+fq8Ky0s8AZGdpNxg+GjQ4lIIiOz64up0ZcCA0IhfK2YUN9N4MHFlDxfL1SAg4HWWK+zZfi8IsA0LVirjCiMA/OuB4gqYu5W8bsfAcjCN2AZudMYi+mMlhY1CAXW2nDny0XEr5bSXVnehcUAgNzgWjqSfLxwFaW6TGHFQJsiVXIGywiug7F5ywOoaMwO5udsqoy3XQl38L50SrIBIjkh1elnqDATenKQxF/VzAzaRQKMzCubn9Ne0zVZT05PaDo0l9WYvnK03sQZc4W2JwN3IaOVSiVPCHmTZAa7Q2tOD609I4oeB0vJtbdITVg7y/AmqLWRhXFOlyU9agysweNP5CzkrdZgfXMHPyhXoXnAFEmO9swfC048k1oG6e/Nngdx6iTAhV9gKrjB9IUixp2biuvUnrJIvO28X9Ce8d9QV0jEHvpSRegTEQm2DrUXD2bokm7tEM2yqL5ytwUBAFec/5tkQcneAK3xQNpyNQOAs8j7mibcAhtbkCvQnUF18GjaDW7UjLvQkBVpWV8ONfsb7H4FE92135NYtIOorphygQcBha8yAfNEcKJvrC2drPBC4lJ2ywsbenWjIGolD4pUKuAKtjVsxkDiWOCu2WmKdIvAnMBXyJzjx70E2wB4SOYqSjWgBuALD2ebsC+fel7UeVlXVk+oOjQcC63OaDXKN3IYFHCOYHkoHuZIrMMdOcIWdLcYV6E/g70KNyiMIOPkXBcG4PwECIv0Jy/cukVj3mRAQKf7Wqy6iiKIJGgsNVOZiOX1nbz1Brs0Bgg1n4/Y3krunoiBXgoHTwitgCZxcGjGmUGyViQJiDFNCBnVyo65XWQERNbQqcy5bmUW1ypcXyI7glgyDXA8CTc/X+31KtQJZS19qDhBYhz6PYB3xmyErYKSo543dXTjxDqeHHUDBe/hvDVmB3ICgvBEBJy+pgOggcJdpwDOgLUt+BR1zjGQYcFJbp2h5FR+8SK8IoqRP3tKpHEnjHyouQDM2DwiWK9zXtQWUvAPEYgVIrNKJnGAb2F9xyJR+3r+71p/wKrr3ei3W+hOsgNhvPoSKXqdrEkpHHflXK0oquVHuKXG4zFlwmhZcA1doHhBYQ8s6nZ4rwBW2S7QL+qQnbWsLphzY+VQlXwdH2IV/zrYzBQj6E1zJ5gr8ZtNInj/Bqm4mdR0A/iFsMkaAN5G2UNN16swdP4WCFZ82sbKsEyrsWtyGxcktw/yGS9wjpwQY2EAyXzqjZi65/oS9gPIFjruLy2R/AlW3pclj0JavAOCEaiMFxAJUgAGLyagQXuB++UtNBgIqRKlawbDPryEFfgF2BYwd9UPY6OX8WhME5AqvgiPsxsnMyApYro56RDxHz2R/wkZP9onA5R7l5nIzItq6fNLJPccK1JKaDwTWchwMCWy/kzsRc9y7YKmcJtjt1LvzJwDWkhtLzIwzyvUn5OQOqIv/k+9PeBwjH1yuP3Um5uglXsBJk7kBgOdEsaVACgtKnEdBqQnBXE8qO8wMEFg3C4YN3U9KPIcd1ZP36RK4ODbScrCNrzuyCAr+GE8GXCEDZ1RGUtjelT/x3ZzEH+GgBfF9HK/WV477EyZXwJzt1ggWRRfIbr0b/z0NEESlA0Y6R74mG+e8qdyWgnmVqdnoza+eBcP9DjfePkfOTN4qY2OXoFGnYIQdMC5usdsJWS6ion3ycPxzwwk2v7Epi9D6CN57tXzJeVfVRa7CGk993jfzKwDldHGwGVYzE1s/ltqL/0ux59RqjYUYLGO1LVK/RhOyyGunXKb6xd3T7MZZXAo+FuNKh2PQ14eD++6Dbs/h7y3Z33lZTuhZhe7BTvANBYNdwPo7uJhRDyYKZZgKCqXlyYsRwg+pnR3hCW+F8vl2zdD9+IzkIg/JI4kdHgiq5gS2Oq0BBFsbRvQw4oacolRaZ66HYedvwLI5OqnU+Z8IvE7AbVT+BJrCv+eZkv1/W30laqj8ktI0K/OG1gLCeGUxovrRCVPDsPpwjWsj7zELAIEXARksEmkAV6A/IQEVMCUPghucVREIqAnNROoDYGuQCaZWdWYqP7UW087BfjeqGpZ/ZwinDAxd4ryB1dL3orMuUru/v1zB9SekdJX2t7wKlGe55bhYfkv8Oxvyp6iZ0xpqrb+V2mPyQ4CA87VucV1rcQWes/6E68ENtuUFnBTI3C6XWnRqKENe+v8pHa81D2ByOFO5AlcZ1Z9oRubSu5fBjxbpPg1295b6y27pEoLHEUjOxcoJ+O0Wtfj5t00/HUsQ/OFippo4eX0C39bGKZhAYKQwd2pn5HBGfqG6vmu8qaerrD/hXxF+9rCWb/0J9ZQakGeDCQQS91mMWyYHP+Xjava1T3PustsYVjHTl+GuT9DCZ8+hduK1Ao3s/L3WPAWd/zjI+fBMqVuq2trRnxDHSuYfwp9w6XQLYrXFBS9/cDkCaW1/c9mBrOC2pLDVr3S/WH/CTgiJqzSrDTgp/Vxb3Q02EAY9W8NKZwNG83MY0zFME+V1/sldyPwaWI1FKhc6H3jhZ7UAanKpgfsebCDQ7k/JnimHZXV0ZLuubP1SwYFOJVoQfwsBcY1u9JnnVKqghDbJEnAgoBf6PK6wH/YzTMrryhUqBwN2LEMZNuBkozfBtEnnVtOM4AOB+xC4u5PQG/djCI1MFBrLJbsh5t8jBvGX6k+wC1jLPdmG94MPBHaKFe7i2Lw3Kbswrt0w0+IdxmBPboiZwvEKL1t1skXxsgN5pz2AYLkCg0cES9Td8JBSblnrT7gOASdvzBZ/QimEtgcQ2MId49PB7eAK3JOhGFfAD2jhLwk39gr5vhLHLmAtRak2v9c+QKBPnhoEPYYiP4UzimlSWJme82D9CZdjDSZ8+dQ6ikQdjT/S/l/aBwjsK+uizuI3o5Pa4VQoGYjO31Li/6jsA26QksegLv4sb0NMPj+LU3sBgVyBI5zrEh35M3R9WubAusDNrvh7Sr3QKXbLU4DIudrnz3peilkMANv0YPsabCumftIzSVXwXvNh8IML0N3Y1Qx8IAJP5UrnJ5qdAbM+hHhNfXV43moUIBiKJYIgTHkUaE+OYJvIDj8RfGAneIJ1W6t/IhQOLYnCz5ACIQVCCoQUCCkQUiCkQEiBkAIhBUIKhBQIKRBSIKRASIGQAiEFQgqEFAgpEFIgpEBIgZACvlHg/wHh6r5kLuqaCQAAAABJRU5ErkJggg=="},305:function(A,t){A.exports="data:image/png;base64,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"},306:function(A,t){A.exports="data:image/png;base64,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"},307:function(A,t){A.exports="data:image/png;base64,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"},308:function(A,t,g){A.exports=g.p+"assets/img/kumuly.8dee19a3.png"},309:function(A,t){A.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAACCCAYAAAADt0XRAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAE2gAwAEAAAAAQAAAIIAAAAANAA3GgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGV7hBwAAGpVJREFUeAHtnQuUVdV5x787MwwgDxUQFEFG4wNFTSIxvnWWpho0Gl2tttWakuhCm9b6FhCQg0azYjRdSdoswTRLY61ZaFvTrFSrqaW1PhEfUbDYQWRmGB7DG2aYx507/f33Oedymbl37uvccR58izP7PPbeZ3///f++/e19zrmYHZADCBxAoJcRmGU2ZK7Z2Gy3LcuWYTBc7zSLSc/xZsduNysPdHbn0uk/6EHzzMpAp/Mes0m7zUY+Zra12qwCsMAyvWREM332gXnWA7gWs6veNHttGaChZZwtI2iDmmmAJUZZu9llO81algHY1b6pZgRM+QetAI7zXTJLtocB4ohTzUbkAsigZpoAGmJ252azd9ndfaZZWy6gDco8XmCWpFfCshcAYco5ZqNyBWMwMi0GWPGZZsM6zO77zOyfAatpGj6NNCcZdKAtDlhWZfZ9UKpcavb6lYC4xI0HOWFmgwo0D8BuApw5ZqcDz201Zk+R7hoP03KDaxDmIo5wcekis3fuNqsFgvPOMhuTLxSDhmmY5RBF/vPNbsXjT683ex6wNk0y25MvaIMiP37LxWS3mVXdj8PHPBtRnFDNxoXsyweIQcG0VcGUCIb9DdtQ4rJXAen/ZsIysS8fwJR3wIOm5R7PLHGv2bUHEZdtI4D9mBET3TdVHQhmgaGLeAEpbsDZLzSrexhW/bUf/V+IbY7skj3nw4HONKffRGKy4cwx9wJLg9nbJLX5BLM5o9nfM3pBEIvTv/B+GPY9trmsYjDXvB7dFGbgzgqTgco0N1UCkiFDzX4sJYXQVrP3WAb6eKZZM4d5DwCUcTIgQQunSsRkc3D+JzPHbNPyxVqzt0g2XJrHlMmHaf+/Aw40L5gqzTabxgrjAvkxgrRK0o0vMxM4liWga8zAsXAZcKABRUJwYJaPDnPLZdaqyBbTXE5SM8OsVdeLkQEFWhiTYZY3YJaXtLB6gS8bKgf2iQ/alp9EEJsNGNCIu8qX4Ktu5kkczPoeDl/SiYlqoazhVbMPCDN2A2LBA4CrkT8DBjQAcSHEeLOHYNnhOC3hViYFeWjyHsmnAKvxoGhRR/R78XD+bPF7zS5CoRtglthUDoplGghqGABIcGvu0RxJcTIQmBbGZOUErj8SC0BMo2NMAwAANr5itpLdPV4Epkk9/d88cf7OWhaYzWaqdCo2KbPUuYRAa3JjgNXc4ptm0f6MKvs3aEsD538772AA0Hw5LFARVpKY6LbRN83G8yIyTVXcr81zVWBuo8weISYbDmDO+aNXJ8iVwbKmN8w+5Lip2IBWYIXSb0ELYzIm4X8EYN8kYu0ANNyaE2eaxGd1rGqsYdTEtUUn/RI0DxYpJvsOD3grzX6oKUBXZ6X4A6atJmkgHBEDI5N+CRrau3ZPNJtHTFYV90EJfZnwK9dcqd6Pz3aw66ZWpJGIG3kiqamXKpHzxz/F7zY7jcbfHdhdqh6aBcR412zbiz7T9noRg9bfmBbDPznW4Md+yKS8DFpBtP0WFDulFEFtPUldEGqwG530K9AWE39p7kjk/x3M8kJMUIClsiyJDA8z13CwaWyRy0DJClN2+g1oHqy6Cd91A0vVoHS/YjDEzTf9Xf8vJ2JCkndniUg07YzWn+ku/Qa0sK1HANgIsyO7OH/pIukEtDIY2PS2789avcEKGopXsMXnmZ0Jy/5Sk3DA6WaW+De3FER81rAenzYzolUNbrefdLvxflf7wAFAxABIFqf50SM4f63vtHM+DGSTrSQfp91TkzqSRmK4wIqTWSLZ6fPmiR9zHTufJR8m5OfI+acDTGgAmkONcGMtuzuI4wYfaB7+aQmsYso0DpY95OiW2Q+LZWUK/RkEPiVpXhgwj/1MIpzzlr7ONNe+CWaLCDHGQ5twQp5OUcVnMTLs/tDsMzK0heaaJnMIloDOW/osaF7g/O8x+yos+66cP9KTD9bKhh41ba7n2WZ14AdVKFVAKbRi8wp8n6PPgoZpOX+EH/uBnD+aimUhQ1JxSO7rokZOEn2qE1hz8rL8nQYVx665+EfWvw8JrvZY774a/L0+CRo+zL21OM/sz5kuVffk/EOFpLXmV6xsbCDZdVIXf+bh70JkGFS+TdQ74qfMGHQv8jsgSXOSPgeaFzj/G4j8MbcHRTeUDfXNqJRYFIAmpjUzHUgCoWsL/ePOBazwMroe8jOzN6p5JspA042RGW8SXOhzoNEu1ybChblh5I/Sclc9iQAqk/aBeSYXHT3OLwI0UO8EuEdhYtWPzZ75Kq8qLPPft1XZrJ1CnqT05FiTmXprZ2mw7DPb7IugdHugeTbAXPOENPn3rnePBSwOQA5IpQLMM3uMweS0H2HyJwIS06yt3OdgygwDxE0UF3Aqk1X6FNNCk6okJsOXCSw5/1za6JaD0HjXB4yexzKIXEM5DzcXMGwxFV33A75Qob7mKtbaSFXxOWu1k6fk0qA8qywsuxyyh5KMalrzvxTnn7rm32OloocUoYzA2H4urHk2GH0Xmj3O6DsLZuH/be1MVj5eICsH1bDskH+FcazR0U89skwsTEqfAM1DZ0X+tKqS1j8Q2ImwyEnEJimC+cnM9lYFE3Vo9QtiihtXm/38ZV5OngGoTzC9up0nVwwwf8g5va4wBIDbSDOJmiM3JmDF/lifAK0hcPT0/p0HmU0FPQGYl78VwgCxi2SnB2Op68mxhBbreMf2ST60+CLxG2ar6wrO/qoZcD/iHCu7GnR7kqDqffk+d9C8gGU0fhLdOAcTk53k5PxDTUUFacbIKKa1ElY8M8bsWxxsY3D5Jec+Od9sC3FZ6yN8prjT7Jpfm/2W8zGAVQdlEwEbZ6Nf/OWnbAVKev0kf9RS7z8Ay0ZjYlJCAWc+UiZtWOLecbfZ4lE8BxWlVpothcVvXE3A+2Hg4xgoHloDwz5jUn8x9/KyM42a9hd10ucmXjC/nG12NoC9JrYgSvJqlzKDdLwRpz7JbIJoWgtYjzHRP4/vBjDFHSvIciajJc7rP99lmWmC2b/DxC1kzWaeZNlfPlfzXBj0PqPl9+VlEZlAXoCpkAqgeQX0nCCFdmCWAObMEgC3A5iIKG//KOa/it0POQGpHWB53+9zA81DSVqrJ0vXAtr5KCPA8nL+5He0VApoGkEVphgOHldmb2KWG5cFmE4z+5PhZmdwr99wbcfJPmgCrH+A5uH82eIoNRJ2PCAa0PK8G0+xpABaAhMvx+Te/jdGy2qeERBKaFxpryLq5z6PTISB5FvOuV3L9nVS3sTJuwA3LFpwzm50PJ6ve1H0GEDTmn9eI2aXRiSgaDnOf8+rZv/ItU+qnZX6dbKSeztMO5IR9XcEZp8xUjeRR50kYjrTJc1Zeh00LwgxbjOrovfvKSTEyKTd+zCM7X8uZirFfQSIRuKjAOzeI9lZ67NscxBmCDS5BOXLS3odNFrn7klYMA8fMwpzkWLFtEOvVWmFY8vrjIj4qvqXmF9WB+Y+kjckz8INkGcl5z/AJezxuGExUkxj876vF4QY9/hL2Ddq+KK783b+qTemfMgUVdcw2TfLsmU+i6ZfZHYzzApZtu5Q38+JZQVLb4KmhUDnPxjB7mcTYPJlRSnQRfM2QEt4AZBf5jOfL8FC0Gx6y3+NdNtiH0zpHYLdpYrsh0X1cvbq9+XwcNSgE5/P172sOlyCLxOAkdw/BfVOIv+KJb7Jz5jOzGAEN1nPyzBric0ux2zJq+wCrGDQeotpMc/vYTmv+4JWd9LqFH1Ro0DBL0qUxE4J7nMZLJvCiTa2jf4AsB4QdSgJivgH+f7tFdBmBYyCZTfh/L9MyzVqFcyygCJKnPKMwootZPHlYhkj5cypZmehXCfz0b0rzPhn2xf67FZHFaV3UYW5eVbxaKAUuY7JODeb55xangwTOuEmjUG7E6BildQNaorPmnf6bwmR2MgLCDFw+JJYC3FZDVMnRs29lA2r8a/u+5sX4wvu7X33y7qnjkkcTYCJf5mMEgoxRI4eRdpJpA0sStoxoHcSmcZAZ9tuglVmAKtfYXDk/HqyfXIma2XHmh1H+VZuPJSlXLGsnlit/Vl2EFVdlHmWFDQPJrDFbycaR/E7sgWy6YCSdoolYJNby96K0gARe8f/NarHOd2oLNfzOsJTsOwUfuFFdkrPDOF+7b/3R82d3r7IP7wNuZKS7lzyYtedkoLGzRzLYJg+wRktJTjXjWW0WA9AytQYMUsODxY5kGCSQ0WgAWACQGSSnx3C754RTtRWE9Su5ByAtX2d5wCTzSZSvpW6hsLG2vdh4sWA+pLPMGpxkhdIYaEwLRloLDO4t7DvNDsJlv1FwLLU+6nhDixCEPe2D067YwvlGrggsDBDN1qIOaPZQtmMWe7gA/5l4Mqmehhb7KhjeOeDe+lAH5ep/GqSuir/OrvRSKoS0dTYpRYm5HNhWUWqLxOzoGAZipWLetjXu2tQrJ43HQEuCdShQV3Kw/kEDCsDlPq1TJc4BXbW7lEHm13BUvlEsIVl7dRdoTI4uXdJtnEelxedlAS0gGUdTJf0uuefAZikIgDLjXr4qU7A+ggq/OplwJiK0swTtexNNvfKlPNjMlWdP5LzR5AC2CskH1/tW7DzmRxPncJqLKlMOEZnxGDZjt/5C45NCynr6WJEUhLQWBqV4obZzWXTk291fHllYIaY3/s46Bf/218QHM+I9xTsGNEKI/Bl5ShuB7Phn2wCG0AmME99hbLlBUyTU5ufhZkeHUFq3+Q+5KuknLsPdYmZddxXy0Ct+EnXHk5HIpGD5qEIW3yO2dcA7AoaLtMYAmBy7A0fmT33Iuv0HK442/9sWq8LjGSLA1TF8Vw4nE2miVm7kQSN3XPNtfwaFTb5IUDs+qlvliLidMD9FqlYptVgEufPakg2jo3YNFV31KC5SblHxYA0RyMhva7RTp9Ev/QLHq2x+9GVHOLIRwLAM+SZAEjtUwD2MC4exCZnrjLaQEVvbJdjbi3LzZZxSkC0Y556im7fYMQUyOQVy/SKlhtUGFBWcswA6oNIGplECpqHcjQ6PheG4VcuUitb6HRWS5/ArJ7/gtm66wkDyFdxAsdsXwCs9jEoq4bAKKehtJcEoCc0YDCarljNHHKWv1RdtszhaRdQ/sqgnKuCTorB2t1c/1+qaPFKAJrMPzJZGJgCSupJuZ4K1T/Pc0YA++Uf4LxPw497+CJ80L/AkOlfYX+Czw4Xm8mOJQJLm4RUv6ttH/smvX47Pqo6AOJi4j+xDNCEc4zUvULazH2J6+pm+ue5FK1ExjTP9yfyZVfhm85vYDnmUX4Zj+a+ehkK/DYwFa7/A079YimKppUCKhWkVPXII5aV4QvrXuGByRn0AyYZvtxySZXZDMomMGGZpeqhiPNndSSNVT4bdSpSiQQ0Wpr8QALnvQhT2gJgD9LS5TMwx9OZUANaYoH/84LXwZx2wAoVzahQCCa+71Uy6SdvWt6EzTp/Lj7zCFJ8mQuQg0rENs0mPiUpiT/TfSIxz5uCAcUjJiMaP+ZpvsOk7uXVDPmwQ35Fi493j+DpE6bTgaIa5bKJW/sndNj7hv9zhJouhWy6qsqsGhaqrvKgovC7KI3Sazi3d2HAvOB6ZEkkTFvi+w69T/FdnPUD6/3XmjZOxv94XMMk/5Sp0MMwTBISyD/K/Nf5pyZ+8LKGERf/1YxpynfZyfjMI0lhlVvIVIXaR5lYKyb8Ep3FqZ6+I+By4VI007yAZQtgGY5/+XNmz15OSCaGCUwAuxDAngZQiZJc7+lePN7IOxmUWTfRL9tZafbHx/FOBqztoLIkYwHOxXJ0DEVsE6YcJy2J5KpA2pt7AMAWZ7o0qo3fKyPg/Hsy7prOxvm2O5neDDX7tRgAE6REaErs9ijhT0Ts/o3/G467n6ATVGIyZi6WqeHUuZ+IcZh/A4k6TR1UEikKNHyM2ikFzqB7/4Pd2uvxJR6A3cxnObDhRZgxktbLrPJxBe4nIvBnNYCw+grqo7ydyO85Atj0Q+gA6uzaAY6Ze/0Fkt0ndcdUVUQi+SjS9YZu6PcABb9T8SSLfdUo85Qb8UHM7J8AbQpKSGGwy13UE2IRMdm7JBuI75pgbDkHdx3FiWFs6gXXY6QS7QOk5pwyz72rSghawUwLTYMgcmKdH33vqQ5MaAHTIwA7txDAUFi+qZyyLYD0DsdNHmHFOt7OJmA+dSzYcO+una3muJ/JgZkCjfGgdFIwaPRs51KUY8hv+xWrDjNpowfTAOzBkbzWhAMSGfJiGPklzjRhby1sqan236GtAIzZ47lI4OymWqks45SYpm/XW7f462zhdwS6FLl07bG8bnA17b+GKcsswFkCM+bhc4bzJAiWgGU3NuRV924eklBg0zLqxb6/jemdRDAbpxfcAmMX0MRO+bQ9ywmsKaeAt2RSMNPUIhrW6TEOAFjzXQwG9MATGiJ13k/4m4eoHJv7XKfRX6XYSMcMB7R7CGT1/625iD9dlZTTTcHadqgz/cN0OYs/VxRoHr3O1nYb/30QPux5WKBlIH0u3XVks1xESIsxmPbO/3JzdGusJTCmzqmYZXyUX3+3qsIeUjkuNk/zQeuWL6oTBYPmoQCbiFUxmlULRrTDcWKQonCzRPlwFlBPoKy55mgAcz+NczhgMoK6sEKsShWOxVDdnGLuiV/q5cj3CwYtbMl9mCQsO4PhqlDHH1YVmrWeDdRzsmYrLIOyU8VeBgGt1WUUXQN0Ig5rLWWMpgYUNBAsZoXiJkDC8d8BYG7VgrrkdooVxyRAW0lFwwDhNlGZ0TjG5hxVphvIRMmLhbrOy5QtkvN5My0EbDavS+HDHmWkVA8X5MO6aOAGAdk3DHtvCt8u0aNTOe44lPox/7ShRliHQIPqRCYWX+WaFF6JPs0LNMVlYtitPJgltHg6QEqBeF71pFMDpd2vt6C4woxmRsoblU+dMo5NNBYw6SQwTV0XMbHm0krOynoAQ0wmgBRgPoNTHksLRYwoWOb8mSqiwjUk58HiE7lZBw0sH8OJTIBxSddcKALgMs/Ewp6zq0hRkjNo3MXlnW/2E/zY2VE4/tSWh4oTaO2azH8dKfbQKTHu5f4rxJ5AC+uBYurUkjMtp4Eg9GP3+l993KKIH6X0xDwyoT4FtQlihqkANUWac1wmlsG6HpkWWSNyrCgr0zzAkR+7w+x4Gv/zoBsje/UztZ3UrcdvVZipiOZoQ0Cb9GfuZGqBYJ/zLk6jfXgNHlIE5dNkjeRUj0yTydAgOtzKaPzTtEivDuA6Igkv9lNAgGBbmg0kRxXdiMDZOU3tK086EeN1DbClT1YipKsjn3M93mBR4OQX8PuLLMt8BcDk+NWwBA11G/vyI2m3lDwiqHTTllF0kXsktRYQis9yFUBTZFK2MNcCBebLyLRZsMmDVXP5CB/a34HZiHFak9c33GKg690wTb1/iIzSNFsIYFhEI5/7CXzdIARN5RRmCDTtZxH3fIB2EglZ+bN+07IUKfxyWtBYJShfAmDX8h4KDXmcTYg5x49SCWi1l+Mm0mYUagEFWVVoPvIveqZZyTaU3h/OTQ7SMWDrw34HEMdOhKDAksgERWXRX9QVAj3FZ1wOxVVHOWHs/Fp4oRRpWtDoKelix/vx2MRG5oGEArXbSDczL6xndXQNoQFZNNdT/CmCuDKkErByg57wHn4MGwHqaCL7McR4Y7ChcWh3BOlhgHIYmcaxDZPmAg1X4AAUAiFoIcicSiu6OXmJiZ2Jps0T1cluoIllgNYxnxdLmmDQa7wt/bL/o0cN3HQ7G6edbu3Hkm8C1kNj9WhtPyvaSCbYElsJcT4NNk4JTN1TbBCRRrAddobZ3zEhPxqmdFCX8rgeUCaxbr+KdbG7uOCWTlCEchDtlwjnHIq6vHn96QaaANMNYdRbmOjr7A87FfBO8Od1IkLHtKAxHmkNJ3oStXpRYLkAGKNsDPQVWlQ+RQeczi8XcMOjAVYDS7mQVBk1Ih/QxDRQOhjwxwk01ZGNnWQpSLqBFtTSCWAbLqfX8Df6xZS23wdA6boalasEDZcOToKyOi0XJvu+ZQQpJunew1VGsUsi0JQxWVgnM4hAo9zB03nfjfbGFuVeNEONmU9nAk0N1QjZnLlo4VdQrGIFoNEp34BR5zILSMC8ctFYG6bu1q3VuBA0pZkkuJagnOLJSeRTUVVVEskIGg3JpYMLaZQ+nND/52RfYr1M5gjb9LqU3gB3o4qcJu7BOT2SrBJ0sD7J1vBZRSKS9j5o3LQkshQ2AFjHHN5RQ7OLsFF9UOGcPyxJMusE9uXXtAngbKIeVj7MvIpEVTHgJ6tjNzoJ3Ud0NWapaVXAYEbJW4UUyur7APegF7Y5R6dUIDgkSXMVlcE/HkcyXoNOruXyzderoHmYIJt+7usCQLsU+5GezkVIw9SNw5z9A+XcAkLgDydW844cA07Gx32quxjpTdCEiQY5BaG3ytkjIlW+IqBVT2i9rk5Yqa9ZtEBaCdXOZrdiUYnYJkV6RfBl+laqYx4Tf6i1XL2F9lK4p44TQOGmdmpEd+CEhXRRsQtbK0zbQrq9nl+Aec7sb7m2g/zKEqk404i0xiyVocQdOGtNVqUrpHMSAhMqKHDcBjjufxrTBVELYBLEQbsovJkwZQMjbR3Tu7oNTO9W+DOXzWRrnEb9pQBMraXe0svVsAwf0zGbF/8IMd7jjgJLGEgce8QcmZcaJICEKJve49gOwBsJS9YTz9U2Ag6Dyfqt/nto4OVGSXC01qPAlDAmTrk2AlyKRs8y6vSdsHZKKfS6+7oEPyaWDYEhCmDd4Cj71GwfDXcBzmb2N/BuQR2T3No1APSx/+rUFrLolQOwc6FcGwFy21gAIjSJUyZB/gQuQMvwIVvJWhopOdNQxPkysYx47H1AKgMg+Z7N0GM9SyXrQKSOEKF+vR/TQiLHHizPWicBzikAQ9Aq8jnnTyd0ej44JQeIe3aTkvs0TClUrIyVj7uwzZa33bdl7oNhLM6tmoh8rZhWOwC1Q8EOmNgxkc2jPI49rMMpgKl/rlJypkk7NJbfkuKQTV8iWvsMNnoszok4zJGVJjw/z34Acb7PSa+AJq09zBITFLM7YIpA6vPg0MYDcgCBAwgcQGDAI/D/uALuV3BxyKAAAAAASUVORK5CYII="},310:function(A,t){A.exports="data:image/png;base64,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"},311:function(A,t,g){A.exports=g.p+"assets/img/atomic.ffecd305.png"},312:function(A,t,g){A.exports=g.p+"assets/img/hydranet.e412d0cf.png"},313:function(A,t,g){A.exports=g.p+"assets/img/cash-app-logo.86558a78.png"},314:function(A,t,g){A.exports=g.p+"assets/img/aciedo.37b33a98.svg"},315:function(A,t){A.exports="data:image/png;base64,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"},316:function(A,t){A.exports="data:image/png;base64,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"},317:function(A,t,g){A.exports=g.p+"assets/img/lndk.abb38b97.png"},318:function(A,t){A.exports="data:image/png;base64,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"},319:function(A,t){A.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAACCCAYAAACKAxD9AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAwmVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAGAAAAABAAAAYAAAAAEABJKGAAcAAAAyAAAAkKABAAMAAAABAAEAAKACAAQAAAABAAAAgqADAAQAAAABAAAAggAAAABBU0NJSQAAAHhyOmQ6REFGaVhpQjhCUmM6MixqOjQyNjUwNTM1MzAsdDoyMzA1MDgyMjAda/UAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAMjaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PnhyOmQ6REFGaVhpQjhCUmM6MixqOjQyNjUwNTM1MzAsdDoyMzA1MDgyMjwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjE2MDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTYwPC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPHRpZmY6WVJlc29sdXRpb24+OTY8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjk2PC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KyH8rjwAAFbhJREFUeAHtnQu0HVV5x3dCEiKCPNSAoGjSBQiFshQEQa0RKrIwRSqvYpFVVis+66oP2koBWa3lpSgt0hZbWEArVOQhCxBQoKSCGBCLvAQKKY+YEEIAIQTy7u83Z77TyVm5954599x7zpw731r/u/fMmdmz9/f997e/vWefc1OqpdZArYFaA7UGag2sp4FJ6x0N6MG6detsZxGtLV3HiQyTJk0ynXAysETIjb8RFp0MVmPgtSNZl3um5Nev4fo1I10/SJ8PJBFygyaMuVpjcSwhtgVbgy3ApmAaeDnHs6SLuH4paSbc4+cThhADRQSMZ++fXCDAnhzvD0x3yLEJaass5sQj4FfgDnADZTxNKon0EhJiQg4Z6qAyIgFyg2V1Jv8BcCVYDIqyhoNVLVhdvCDPP0B6OtCLRJlTOB6ojhNtq3yKYSSALjwT8juDy8AKEGJeSACJsHYDkAx+HteRzWQhf08ADiV6h0lgauNp9d++0IAGAQ4FGmgGOAm8AkLC8HHcbipRghhxz71kDgPxvGnkjTtq6ZUGNAbIeiWp7voY8BBQNKIEMO2G6EFWFgq6gvx7ou3ka+8QyhivFKXrlg3cMiE/G9wEQnTr3SJAlBmpHsLylZfAt8B2VoRUYtbeoWGWsfuLktcblzUAuAgsB4o9Vi8w1iLJggw+63HwOTC9QIgmUcdOIxOwZJRsHJD1NtLNwfHgWRAiCcbKC8QzWtOYecT5u8n8HshmFKR1/NAtrqLM1tnAkZz7BQjpZhwQZZZNJYRDRsjFZHYLHZBvzmbiXJ22qQGU5zDQHG/J7wsM0ELGMg6IZ5RNizOMpdx8KtjKJpPW8UObts8uQ2FZIGiaK3Ab8meDF4AyXnFA42nl/zo8vVq47RHyfxI6IF8TIpQxVIqSnAJmQRbppuBTYAEI6UUcEM8umxZnF957KyhON40fsrWIofQx4c6rELBxNJz8AeCnIMQ4wHG4iiIhIn4wPQ+8vdDWvosferJ2jlKmFF4MGWB9GRyTK8o3htnLo/y4yomvsn1ZpcdbBL4N/oG2L0MHLkb5MmvE1+NcN+YyrkRoIcDmtO4r4BPA4EqlqZRBW62TCKtAeIGfk/86BLiM1IBSkqztF0JYpzETGwuaYyP5o8FjIKQfZwNRt26lDhHFBanrOH5nKJ18T+OHMfUINE7jOwystMEcv4/kFLAfUAZpGGi0aOS/ttkpsrrXA54FzkFHT5Gqo2mhL4/HS8aMCDSo6fLI70SDvgSOBZ7XVaqMppcgP9Gk2AmepPGng4sggUvn4x4/dJ0INCJjOw3SFTorOB4cB94CisEThxNeWuOHn6KRU9HddWoG/TU701hrqmtEyAngPkGNbSMOIzkBvMNjZAWQ6RPZC6iHDYk6EwaUestrwF+iy0dJgxBjul1u1ETA4JYxlUpHHOD+wJPAwUDRBXqNnqKWoTWgd5AMmUclfRH8PXC66Ys2dWi8JVG6LqMiQtELkH8rtfsUcE1Al2ajlJoADT20+zcIoQ6Vh8EZ4N8ggcOtXtXt+V7XNemYCJKAyrjyZxmfBhJgJjASFtEQsrV0oAENXVx/uJHj09H5reg8G17Jq+euSEdEoCLZyiDpW6jFd8CBeW2MAxznOio3L6NO1teAQ6sGV6/LwdcgwGl5B3TrfnhePupcShuMChgP+B5gLx7772AHIHMtq/YCKGEMpNU7XMozjsUOLlBlnXK0zyxFhHgo6ft48BXgjUASSIBSZXF9LeU1oGdQ307LfwQOAa+CUXuGto2H8SMm2JUHO15tC3RbtRdACeMsr/C814Dv4xWOwDaZHcl3HEC2NafnQV7n5ovNSC8AkiA8AdlaxlkDkkBPcDg2OSEnwKhmZ20RgQfqDWTbSeBdQBI4jam2rKNJTeB11+l5KyPTqakVPhEy7IN9nFp2TIYRhwYKjxnCbB7q0qcVUNolUePqfvu7Fh1OzpuwhhFuo3yEkxiTRlRLv7QmhuZbIML+2oqKdbQCOWyLKdjPhd7gu+AosBI4lamuBAmWsXh3120pPbuIsJfR7h3vTmnzLRteohpk0C56BRn9ccjwXWzW0dvLkXq10agP2hscDpyzVjs4tMfrCV5eltK/smB3zodT+vEFLOYexIrI36X00m8aHsHr+l/spNrH9KjcIzhEeFxKRiJCFOZ7AwkQ7IvzFUtz42rkGy5P6Wdnp7Tbn6b0hlkp7f7JlG5na8A98yrWpmwJX7u8H+ydd9x27dps67A3UKhLyK/l6jn5HcNe3yy1XzMx/t93d0pXnZLSrENZq3uB+BvvsJJFu63YMLR4QSNorMbQoKa1ibHCpmBfoHTPI0CAMPosCv5tYHeKc2QrJhkJqP7zS1kPPRMv8DuojxVx44VJNovmrSX8WUtqS6slYfh9sJtTS6f6ca6tlgxn2PjM/QTmYyxqq+C+uijG+zWEOFddmNLSx1mOYUlkDbPgrOfnljdRfaVUyPW9l7DVblRli3x4KNWKKGC4pvguQaleP2nUm5rb69HLvLkpzf2XlGbsyEoI6zGZJ4iLSDPVVbKZ1tyKvwm8DihZaxrZkf8OR4TQyHZ5MaUKHvnR43RFNlVknWXB4ylddhZDAqOcnmBDespaXMlmWmk9tvHc60FpGY4IUZhjTjXFIcGp4qsszV95AYHhc7yu2QQiGFsNJcH/oT7v2/NR8fAIpSraDhHiAaUK7quLb/sRP5r3jywaMSSsYHZQnRlBu2rUI4Qr62ixrx0itFuZ/roumw2gm0f56cRLvprS9h+EBC8PIgnUu511VB12MIlgcOiQsOyllP7j24ycxlDoKWYPqm6wJLxBx60aQCIUOsaNV+AR5rLUQvy0mjWCwRsSOjZ8642DR4Q1ThVp1j138u2Ab/DryywcrWLhqHWq2KqJCX48WEQwLtiIqeJzS1L63jm8SXwbBNDCnK9lWA0MFhGMC5waXnNJSk/fR2zAkODCUTOgHlYXE/rDwSGC3kCZ919s6zyVNTaGhBW8TCo9JIw67mrUo2J/q723IJQds4RFT6V06WmQgE3Wq1hEKhscer0zi2zqSVrmfmNUPVJFpfpE0HD2+hUMAZd9BwIwO3gtaypZgFimd3Otbx+nTP3/bWtljBqPyuoTB2UK6O21FScCJAjFz70+pbvZbLLdnpCg5OqhPd/p5eu2T+nxh1K6xa2Zit08JIzrOfP5Z97rW80Z26a0y+4NIkWd4tYKpNUmgi58MrOE+Q+ndPmZKW2DIdYwVSwdHGLMtbyIeg3/5eeJe1O679rc0GH8ESw5GQ+0fH5KB/1NSkcex45Ovn9SMTJUlwgqWhK8yA6jS5gqTuFlkjuRV3YQG2R2xujGGtN4gbe1r/UlQdEjDEMGh6ZJvNW8+vN4BXY57fGeyhGhutFN2OWmq/ni+A9T2vLNje1mZQK8KKOYSgZ3Lq0m5shS8yNA8kmazSDQU3iGinkDm19Nj5ANCXDYvYc/+FpKb963se+w9FSxyIBivs0hIW7JLufPqqUsYm2FdyCfzTxKlhPl9SCtnkcIEix9hm9anMWG012ICwj0eqnzyfSn5c/zK1GzU9qVYLWCUi0iZHEBVdZ9X3tpSkseaew9XOvXLXrFhDxWeeF/Uzriz9jzsHXDG1RsTaF6RLC33XErX0r5JlO2t+OOe7iErHeaygauxSxnH0ig6DelKjYkqE6lOkSIIWHhk+wxYKo4Yw+U7pYzemQvRK80lWniMuKC7fdi6nhkoxbGB6MNWHvQnmoQIYaEVcz1Lz+fwJCdRtOZ5rkI1KshwbhAgy/7dUpHf4HFKH5auqLeQN5VhwjW9j9Z8Zt3ATuRZzbI0LVZgoWXEIk5jSFhwe18I/REfjyINYTwWCWK6adL+58IBoIGXo89zO+D8EJpOxZr/Hpaz4IxSDCVXwZYSnC4xx+ltN/vN+xZweGgSMT+JoLjsKuHL7/EC6Vz6YW4314rXC/kAtMUlpUP+wRDFJ7Bdw29rlfRqh3k+5cIul/Hf9MbrmD18CYWa7bJ44IOWtqNWyTmFLzB4rsZEr7MugFDlCRwV1TFpb+JYC978L/ZcXQGL5T4CmYnewy6ZSBJ4JdjlvxPSr/7afChRskb9a8KyzS9T1uBFzAG8BtKP76SIWHLxhCRLRyVaV6XrtUrTWGq+MoyvmK6LT9qd0xjKDBA7NWspUtNi2L6811DPipkm0yWPMFGkxmNcTlTuh+WEbzKaEVSGqss+UVKX/weq4cMURWfJbSqpD89QgRe0xiPt/mtlFy+nb5ZI0BzjDZqNy1iQ+fsxd0Qy17IEHXwySm9c59GiVHHbpTfB2X0p0dQMfa4jTHkHKZoD9/GhpE7CMqI1LPfNGhDc+sI4tyjsMXbRhfRu8fB1cOZTFs/9NHGgwfMG9io/iWC7tixeeYOKZ18cUq/vKtBjnaGB0ePLMZgveH2qxszjU4Wn2Lm8vIzKX2WZW1fMQ8gCfqbCNZO96sx3A/4wY94ppy4ofXOGxoLUBs5TMiQNiWbJfCzRE/+JKWPQYKddh1YEqiR/vUIYa8gQ9Y785PGf9q0NQ6Mc/4OUsw6oldHee2kkmAaw8pzT/BG8fCUZh/UuGvA4oKiKvqfCNZWA7QaoZUE2XV50yZDhA3dk388fMK9bml39dBnHPnZlDbhBZfk6GR4Gf5hffNpf84auqmeDRFm2PK5waD0aVYPjzqBbXBvbQwJA0wC1TH4RKCDty96A2KJJY+m9L5PprTPfo1bW71R+wVW5srBJ0IZU0xi0chfVdmc4PSjf8x6BUOEs4SaCGW0WPFrjQH0Bs+ycHTUl9jz4N7D/BV4xZvWTvVrj6CWsqkiK5cLiQvmsNHE1UNnGy4rTxCpiaDB3YD60uKUZr2XvYdHTIihoJXfNRHs9cYByxexHZ2p4mabVzEuKBUSt5LA43aIgJYGVfJZwqKfp3QoQ8LOuzeGCRejqiVOkmOiTGBTXtppMWH0AIpDgusFv1nI/2rgZdJ+c6rcSD1CeIWO7DUcEYJh+MxM4kH5YcUTp4QGietWMySwZuDew2yqOJxK+rbN2saKrwK8Ki0v7bT60bzYIEb5p/TbHRLAdwkLbuaF0l/zBZVZEAJdVm9ICM0GEXBvTSKU6rjDESFig3sp3LxzqVKFc31vReq2LgZJgum8VVz8AC+Tjk/p3bN7W8fuPD1s9SDFvZj/045SthqSCPk/f7Ca88GvzCDxwMZRv/9VFcKZQTYMUH13Gy1/kd9TmJnSRz7OMXFC9VcPw+jzsBsbK5v/p7NtCw1JBEuAWf7jTwu+Ni+xWkTYGKNvwkKRP6y1CdPCjfEEBojP/IwhgdXDrVlKrv7qoTbRW9PINDe3U+lkWCIUSruGvKzT2Qb7Ch/3WTYLBKmmRDjgD/kVkx+yavjLxlb0+y9iqnhG45vLxgXVf6vodFEi/ATMy4eF0h1Www4phX8QxduX9H1wMFgJ6FYVkvvZfXwPXsAvz+7EWsHe76cFvFfIiDCsCvq9kXZKpj3Zv2f+DN77n7BZR/8AdEQtUHD8S2An2j8APlxP0q434dIeSdHQq9GX30pyQ6xS/Kxxpop/JYGbi3hJkv2rP4+Jj7N/2mq2bWnHmP7vR8lgnHAx8MHZA9t+Sq8ujBmDgeIUvKckMDAcDBKoVTuytjgJ++ip4z/3ki0nIxKBB+gBhPIVcD9waKgGGahoIw5QZzTDtYIgiJ9VV9iZm8UGX8dG19NZDew7tsmIQ0PoKX+Q3uFdnLsRbAkiUInL6nR8NMB3ARNLoek6jJ+tjWMXslmn7agGI3qEKJWHxBBxF+c+BoKRLmvWMj4a0DOrd0lwB9AOMc0Pr+2p0tI2ESwZMvifyI1Kb+DwUPAccEbh+KR3qGXsNGCHc1rInDjdAuZgB1cRjd9GrftSRODhyqqcDEzO0/7gTmDMYFkSYlTM5P5a1teAxtcL2OHU7TfAARj/OewwqriAcprSdozQvCPP5EzUQ7DpP7Fon/4csHyXkcEFDlHL6DSgF5AAyn3A2cHV6Fy7kS0/TbSgDUnHRLAwyUCyhgqRzYLIL3B8lJ8hRrB6iU68jvdPVLHXRxCufRx+9QL/jJ6fR88SY7U6J+2ajIoI1oKKaWjHKYcFjz9McgrYEyiyWu9QE0JtDC+tnedCLv9bdDvf29BtR6uG3juSjJoI8QAqWfQOGv7zwOFi+/waiSKbu/bMvNxBSIwD7DD5sme6jfyJEGCujct1u5ZjrxsT6bpRqLQBTBbFkn8TtT4ZHA02BTZWz1DHDyghF3ViJ9IWvu7/Fjhfo+cEcIFg1LMCyhxWuk6EeBqNmEoDbKSM3ofkL8AhHiOtLrBxdmL91biO85KAt2HpLHAeOls4ngTgmZmMGREsnQbZ8/UQK/O88cNpYBegTERCRO8Or3gpejgDHfGePNOZU/FVHHc1GLTs4WRMiRAPhgRF7+AQ8Rmgh3h9fs1EiB9a44B5tP0UDO7inJ3G+Mk4IIji6XGTcSGCraGhPqu5AMLxTI5PAMYPrpY5jHiNrnLQpBgHPEbjzgVn2+sRYyayvSFAKHrciBAPzAnhdDPihw/w2RfBnPyaotLitqqmrXHA+TTEt4UL0EM2NPSaAD1XrIoA2U4nU3A0eAiEuJRt5FxFccXV+odcRWavUDp52zvunTCe35dprpRssYn8G8ApYClQJIKBZlUI4RvaFSDkATLh6Rwep4AIEvvSHj2tFMpxsGzGBuR3BJeCV4Gicu1l/SzWMQi7iPxfAWOfTMg32xfn6nQIDaAsCdHsMeTngLkgpKjsONfrVILqtRTrdy6YZRNJ1yP4EM2uTw+lARRYjB+mc3wcmA9C+iF+cBgoeqlrOX5vtIl8HQeEMkabqswog/wbwelgOVB0w70ghAQID2A9HgZHguw9AelU0PRqUf86HaUGUOpklRvFkN8FXANiPNYdF3smh2MmPksiKE+DrwL3YDSHAY7r2UAYayxSFCwhmgEX+T8Ad4AQjRTkiHPdSiVaBK56oQvBzgUCOJTVBBgLww9VJgpvEoL8ZuBz4NdA0WDd9A4SqzgM3MzxQVE38g4DNQFCIb1IMUAxfpjJ8TdBkCDih3DjfNS2eG9rHDCfc8eCbDpIKgGa3qkX7a+fWdAAxtA7FAmxF8d+2SMIQTab0unOPaeRRVHC8H5u7y96ADeIngmyOMBHk6+9QMEGfZXFOBKiGamTPwRIiBdAUSSEhjaeCKN7rtVz6AHOAztGQ8kPdBwwUOObxsJwvMdpfPWL49kcHwjcGKNRtwEbEl+DPwEeBDeD6ynjUVI9gENAtkHX40GVgSKCRsJwtinzDgVCbMU5t83NANsC90E4pCwDi8FC8Cx4knvirWhP9wdQl3GVgSNCaK9ACGzbMG58NlTKPb78Cg/gK+QJIwNLhKIFcwNHWyONS2JLmKkbReM4Pq/TWgO1BmoN1BqoNTARNfB/zy7nEkH9qjcAAAAASUVORK5CYII="},320:function(A,t,g){A.exports=g.p+"assets/img/teos.e5cd86a3.png"},321:function(A,t,g){A.exports=g.p+"assets/img/vls.322e82ca.png"},322:function(A,t){A.exports="data:image/png;base64,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"},419:function(A,t,g){"use strict";g.r(t);var a=g(7),s=Object(a.a)({},(function(){var A=this,t=A._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":A.$parent.slotKey}},[t("h1",{staticClass:"more-cases-heading"},[A._v("\n Meet the projects building with LDK\n")]),A._v(" "),t("CodeSwitcher",{attrs:{languages:{all:"All",mobile:"Mobile",web:"Web",desktop:"Desktop",custodial:"Custodial",infra:"Infrastructure",misc:"Misc"}},scopedSlots:A._u([{key:"mobile",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[t("img",{attrs:{src:g(305)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[A._v("10101")])]),A._v(" "),t("p",[A._v("An on and off-chain wallet infused with trading")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[t("img",{attrs:{src:g(306)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[A._v("Bitkit")])]),A._v(" "),t("p",[A._v("The ultimate bitcoin toolkit, take charge of your digital life")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[t("img",{attrs:{src:g(307)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[A._v("EttaWallet")])]),A._v(" "),t("p",[A._v("A simple open-source wallet with a strong bias toward usability, accessibility, and UX")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[t("img",{attrs:{src:g(308)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[A._v("Kumuly")])]),A._v(" "),t("p",[A._v("Colombian-based mobile bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(287)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[t("img",{attrs:{src:g(309)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[A._v("Velas")])]),A._v(" "),t("p",[A._v("A way to integrate Lightning into websites, mobile applications, and more")])])])]},proxy:!0},{key:"web",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(310)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[A._v("Mutiny")])]),A._v(" "),t("p",[A._v("A web-first unstoppable bitcoin wallet for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[t("img",{attrs:{src:g(280)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[A._v("Alby Hub")])]),A._v(" "),t("p",[A._v("With its own lightning node, connecting you to numerous applications")])])])]},proxy:!0},{key:"desktop",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[t("img",{attrs:{src:g(311)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[A._v("AtomicDEX")])]),A._v(" "),t("p",[A._v("A multi-coin wallet, bridge, and DEX rolled into one app")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[t("img",{attrs:{src:g(312)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[A._v("Hydranet")])]),A._v(" "),t("p",[A._v("A layer 3 decentralized exchange, allowing trading with native tokens between blockchains")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(287)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])])])]},proxy:!0},{key:"custodial",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[t("img",{attrs:{src:g(313)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[A._v("Cash App")])]),A._v(" "),t("p",[A._v("Send and spend, bank, and buy stocks or bitcoin")])])])]},proxy:!0},{key:"infra",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[t("img",{attrs:{src:g(314)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[A._v("Aciedo")])]),A._v(" "),t("p",[A._v("A financial infrastructure suite for developers and users")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[t("img",{attrs:{src:g(315)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[A._v("c=")])]),A._v(" "),t("p",[A._v("Tools and services that connect people to the Lightning Network")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[t("img",{attrs:{src:g(316)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[A._v("kuutamo")])]),A._v(" "),t("p",[A._v("A turn-key, end-to-end solution for running self-hosted nodes, anywhere")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[t("img",{attrs:{src:g(317)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[A._v("LNDK")])]),A._v(" "),t("p",[A._v("A standalone daemon that aims to externally implement BOLT 12 functionality for LND")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[t("img",{attrs:{src:g(318)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[A._v("Lexe")])]),A._v(" "),t("p",[A._v("Managed non-custodial Lightning nodes inside secure hardware")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[t("img",{attrs:{src:g(281)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[A._v("Lightspark")])]),A._v(" "),t("p",[A._v("Enterprise-grade, fast, secure payments on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[t("img",{attrs:{src:g(319)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[A._v("Sensei")])]),A._v(" "),t("p",[A._v("A Lightning node implementation for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[t("img",{attrs:{src:g(320)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[A._v("TEOS")])]),A._v(" "),t("p",[A._v("A bitcoin watchtower with a specific focus on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[t("img",{attrs:{src:g(321)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[A._v("VLS")])]),A._v(" "),t("p",[A._v("Separates Lightning private keys and security rule validation from nodes, into a discrete signing device")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[t("img",{attrs:{src:g(322)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[A._v("Voltage")])]),A._v(" "),t("p",[A._v("Enterprise-grade infrastructure for the Lightning Network")])])])]},proxy:!0},{key:"misc",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[A._v("Gossiper")])]),A._v(" "),t("p",[A._v("Lightning Gossip Ingestion")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[A._v("The Hidden LN")])]),A._v(" "),t("p",[A._v("Probes the Lightning Network for the detection of private channels")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[A._v("ldk-sample with Tor")])]),A._v(" "),t("p",[A._v("An experimentation with tor that adapts the ldk-sample node")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[A._v("rgb-lightning-node")])]),A._v(" "),t("p",[A._v("LN node based on ldk-sample supporting RGB assets")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[A._v("rust-dlc")])]),A._v(" "),t("p",[A._v("A Rust library for working with Discreet Log Contracts")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[A._v("uMlando")])]),A._v(" "),t("p",[A._v("An educational Android demo wallet")])])])]},proxy:!0},{key:"all",fn:function(){return[t("div",{staticClass:"case-studies"},[t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[t("img",{attrs:{src:g(305)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://10101.finance/",target:"_blank"}},[A._v("10101")])]),A._v(" "),t("p",[A._v("An on and off-chain wallet infused with trading")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[t("img",{attrs:{src:g(314)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/aciedo",target:"_blank"}},[A._v("Aciedo")])]),A._v(" "),t("p",[A._v("A financial infrastructure suite for developers and users")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[t("img",{attrs:{src:g(280)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://albyhub.com/",target:"_blank"}},[A._v("Alby Hub")])]),A._v(" "),t("p",[A._v("With its own lightning node, connecting you to numerous apps")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[t("img",{attrs:{src:g(311)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://atomicdex.io/en/",target:"_blank"}},[A._v("AtomicDEX")])]),A._v(" "),t("p",[A._v("A multi-coin wallet, bridge, and DEX rolled into one app")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[t("img",{attrs:{src:g(306)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://bitkit.to/",target:"_blank"}},[A._v("Bitkit")])]),A._v(" "),t("p",[A._v("The ultimate bitcoin toolkit, take charge of your digital life")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[t("img",{attrs:{src:g(315)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cequals.xyz/",target:"_blank"}},[A._v("c=")])]),A._v(" "),t("p",[A._v("Tools and services that connect people to the Lightning Network")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[t("img",{attrs:{src:g(313)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://cash.app/",target:"_blank"}},[A._v("Cash App")])]),A._v(" "),t("p",[A._v("Send and spend, bank, and buy stocks or bitcoin")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[t("img",{attrs:{src:g(307)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/EttaWallet/EttaWallet",target:"_blank"}},[A._v("EttaWallet")])]),A._v(" "),t("p",[A._v("A simple open-source wallet with a strong bias toward usability, accessibility, and UX")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/fiksn/gossiper",target:"_blank"}},[A._v("Gossiper")])]),A._v(" "),t("p",[A._v("Lightning Gossip Ingestion")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[t("img",{attrs:{src:g(312)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://hydranet.ai/",target:"_blank"}},[A._v("Hydranet")])]),A._v(" "),t("p",[A._v("A layer 3 decentralized exchange, allowing trading with native tokens between blockchains")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[t("img",{attrs:{src:g(308)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://twitter.com/kumulydev",target:"_blank"}},[A._v("Kumuly")])]),A._v(" "),t("p",[A._v("Colombian-based mobile bitcoin and Lightning wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[t("img",{attrs:{src:g(316)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/kuutamolabs/lightning-knd",target:"_blank"}},[A._v("kuutamo")])]),A._v(" "),t("p",[A._v("A turn-key, end-to-end solution for running self-hosted nodes, anywhere")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/TonyGiorgio/ldk-sample-tor",target:"_blank"}},[A._v("ldk-sample with Tor")])]),A._v(" "),t("p",[A._v("An experimentation with tor that adapts the ldk-sample node")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[t("img",{attrs:{src:g(318)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lexe-tech",target:"_blank"}},[A._v("Lexe")])]),A._v(" "),t("p",[A._v("Managed non-custodial Lightning nodes inside secure hardware")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[t("img",{attrs:{src:g(281)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.lightspark.com/",target:"_blank"}},[A._v("Lightspark")])]),A._v(" "),t("p",[A._v("Enterprise-grade, fast, secure payments on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[t("img",{attrs:{src:g(317)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/lndk-org/lndk",target:"_blank"}},[A._v("LNDK")])]),A._v(" "),t("p",[A._v("A standalone daemon that aims to externally implement BOLT 12 functionality for LND")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(287)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mercurywallet.com/",target:"_blank"}},[A._v("Mercury")])]),A._v(" "),t("p",[A._v("A layer 2 bitcoin wallet that enables users to send and swap bitcoin privately")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[t("img",{attrs:{src:g(310)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://mutinywallet.com/",target:"_blank"}},[A._v("Mutiny")])]),A._v(" "),t("p",[A._v("A web-first unstoppable bitcoin wallet for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/RGB-Tools/rgb-lightning-node",target:"_blank"}},[A._v("rgb-lightning-node")])]),A._v(" "),t("p",[A._v("LN node based on ldk-sample supporting RGB assets")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/p2pderivatives/rust-dlc",target:"_blank"}},[A._v("rust-dlc")])]),A._v(" "),t("p",[A._v("A Rust library for working with Discreet Log Contracts")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[t("img",{attrs:{src:g(319)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/L2-Technology/sensei",target:"_blank"}},[A._v("Sensei")])]),A._v(" "),t("p",[A._v("A Lightning node implementation for everyone")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[t("img",{attrs:{src:g(320)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/talaia-labs/rust-teos",target:"_blank"}},[A._v("TEOS")])]),A._v(" "),t("p",[A._v("A bitcoin watchtower with a specific focus on Lightning")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/BitcoinDevShop/hidden-lightning-network",target:"_blank"}},[A._v("The Hidden LN")])]),A._v(" "),t("p",[A._v("Probes the Lightning Network for the detection of private channels")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[t("img",{attrs:{src:g(253)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://github.com/ConorOkus/uMlando-wallet",target:"_blank"}},[A._v("uMlando")])]),A._v(" "),t("p",[A._v("An educational Android demo wallet")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[t("img",{attrs:{src:g(309)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://www.velascommerce.com/",target:"_blank"}},[A._v("Velas")])]),A._v(" "),t("p",[A._v("A way to integrate Lightning into websites, mobile applications, and more")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[t("img",{attrs:{src:g(321)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://vls.tech/",target:"_blank"}},[A._v("VLS")])]),A._v(" "),t("p",[A._v("Separates Lightning private keys and security rule validation from nodes, into a discrete signing device")])]),A._v(" "),t("div",{staticClass:"case-study-item"},[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[t("img",{attrs:{src:g(322)}})]),A._v(" "),t("h3",[t("a",{attrs:{href:"https://voltage.cloud/",target:"_blank"}},[A._v("Voltage")])]),A._v(" "),t("p",[A._v("Enterprise-grade infrastructure for the Lightning Network")])])])]},proxy:!0}])})],1)}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/70.f4cfe9cd.js b/assets/js/70.bcb44f0f.js similarity index 99% rename from assets/js/70.f4cfe9cd.js rename to assets/js/70.bcb44f0f.js index 53698465f..4948ccddd 100644 --- a/assets/js/70.f4cfe9cd.js +++ b/assets/js/70.bcb44f0f.js @@ -1,3 +1,3 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[70],{374:function(t,e,n){ +(window.webpackJsonp=window.webpackJsonp||[]).push([[70],{372:function(t,e,n){ /*! For license information please see mermaid.min.js.LICENSE.txt */ "undefined"!=typeof self&&self,t.exports=(()=>{var t={1362:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,6],n=[1,7],r=[1,8],i=[1,9],a=[1,12],o=[1,11],s=[1,15,24],c=[1,19],u=[1,31],l=[1,34],h=[1,32],f=[1,33],d=[1,35],p=[1,36],y=[1,37],g=[1,38],m=[1,41],v=[1,42],b=[1,43],_=[1,44],x=[15,24],w=[1,56],k=[1,57],T=[1,58],E=[1,59],C=[1,60],S=[1,61],A=[15,24,31,38,39,47,50,51,52,53,54,55,60,62],M=[15,24,29,31,38,39,43,47,50,51,52,53,54,55,60,62,77,78,79,80],N=[7,8,9,10,15,18,22,24],D=[47,77,78,79,80],O=[47,54,55,77,78,79,80],B=[47,50,51,52,53,77,78,79,80],L=[15,24,31],I=[1,93],R={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,directive:6,direction_tb:7,direction_bt:8,direction_rl:9,direction_lr:10,graphConfig:11,openDirective:12,typeDirective:13,closeDirective:14,NEWLINE:15,":":16,argDirective:17,open_directive:18,type_directive:19,arg_directive:20,close_directive:21,CLASS_DIAGRAM:22,statements:23,EOF:24,statement:25,className:26,alphaNumToken:27,classLiteralName:28,GENERICTYPE:29,relationStatement:30,LABEL:31,classStatement:32,methodStatement:33,annotationStatement:34,clickStatement:35,cssClassStatement:36,CLASS:37,STYLE_SEPARATOR:38,STRUCT_START:39,members:40,STRUCT_STOP:41,ANNOTATION_START:42,ANNOTATION_END:43,MEMBER:44,SEPARATOR:45,relation:46,STR:47,relationType:48,lineType:49,AGGREGATION:50,EXTENSION:51,COMPOSITION:52,DEPENDENCY:53,LINE:54,DOTTED_LINE:55,CALLBACK:56,LINK:57,LINK_TARGET:58,CLICK:59,CALLBACK_NAME:60,CALLBACK_ARGS:61,HREF:62,CSSCLASS:63,commentToken:64,textToken:65,graphCodeTokens:66,textNoTagsToken:67,TAGSTART:68,TAGEND:69,"==":70,"--":71,PCT:72,DEFAULT:73,SPACE:74,MINUS:75,keywords:76,UNICODE_TEXT:77,NUM:78,ALPHA:79,BQUOTE_STR:80,$accept:0,$end:1},terminals_:{2:"error",7:"direction_tb",8:"direction_bt",9:"direction_rl",10:"direction_lr",15:"NEWLINE",16:":",18:"open_directive",19:"type_directive",20:"arg_directive",21:"close_directive",22:"CLASS_DIAGRAM",24:"EOF",29:"GENERICTYPE",31:"LABEL",37:"CLASS",38:"STYLE_SEPARATOR",39:"STRUCT_START",41:"STRUCT_STOP",42:"ANNOTATION_START",43:"ANNOTATION_END",44:"MEMBER",45:"SEPARATOR",47:"STR",50:"AGGREGATION",51:"EXTENSION",52:"COMPOSITION",53:"DEPENDENCY",54:"LINE",55:"DOTTED_LINE",56:"CALLBACK",57:"LINK",58:"LINK_TARGET",59:"CLICK",60:"CALLBACK_NAME",61:"CALLBACK_ARGS",62:"HREF",63:"CSSCLASS",66:"graphCodeTokens",68:"TAGSTART",69:"TAGEND",70:"==",71:"--",72:"PCT",73:"DEFAULT",74:"SPACE",75:"MINUS",76:"keywords",77:"UNICODE_TEXT",78:"NUM",79:"ALPHA",80:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[3,2],[5,1],[5,1],[5,1],[5,1],[4,1],[6,4],[6,6],[12,1],[13,1],[17,1],[14,1],[11,4],[23,1],[23,2],[23,3],[26,1],[26,1],[26,2],[26,2],[26,2],[25,1],[25,2],[25,1],[25,1],[25,1],[25,1],[25,1],[25,1],[25,1],[32,2],[32,4],[32,5],[32,7],[34,4],[40,1],[40,2],[33,1],[33,2],[33,1],[33,1],[30,3],[30,4],[30,4],[30,5],[46,3],[46,2],[46,2],[46,1],[48,1],[48,1],[48,1],[48,1],[49,1],[49,1],[35,3],[35,4],[35,3],[35,4],[35,4],[35,5],[35,3],[35,4],[35,4],[35,5],[35,3],[35,4],[35,4],[35,5],[36,3],[64,1],[64,1],[65,1],[65,1],[65,1],[65,1],[65,1],[65,1],[65,1],[67,1],[67,1],[67,1],[67,1],[27,1],[27,1],[27,1],[28,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setDirection("TB");break;case 5:r.setDirection("BT");break;case 6:r.setDirection("RL");break;case 7:r.setDirection("LR");break;case 11:r.parseDirective("%%{","open_directive");break;case 12:r.parseDirective(a[s],"type_directive");break;case 13:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 14:r.parseDirective("}%%","close_directive","class");break;case 19:case 20:this.$=a[s];break;case 21:this.$=a[s-1]+a[s];break;case 22:case 23:this.$=a[s-1]+"~"+a[s];break;case 24:r.addRelation(a[s]);break;case 25:a[s-1].title=r.cleanupLabel(a[s]),r.addRelation(a[s-1]);break;case 33:r.addClass(a[s]);break;case 34:r.addClass(a[s-2]),r.setCssClass(a[s-2],a[s]);break;case 35:r.addClass(a[s-3]),r.addMembers(a[s-3],a[s-1]);break;case 36:r.addClass(a[s-5]),r.setCssClass(a[s-5],a[s-3]),r.addMembers(a[s-5],a[s-1]);break;case 37:r.addAnnotation(a[s],a[s-2]);break;case 38:this.$=[a[s]];break;case 39:a[s].push(a[s-1]),this.$=a[s];break;case 40:case 42:case 43:break;case 41:r.addMember(a[s-1],r.cleanupLabel(a[s]));break;case 44:this.$={id1:a[s-2],id2:a[s],relation:a[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 45:this.$={id1:a[s-3],id2:a[s],relation:a[s-1],relationTitle1:a[s-2],relationTitle2:"none"};break;case 46:this.$={id1:a[s-3],id2:a[s],relation:a[s-2],relationTitle1:"none",relationTitle2:a[s-1]};break;case 47:this.$={id1:a[s-4],id2:a[s],relation:a[s-2],relationTitle1:a[s-3],relationTitle2:a[s-1]};break;case 48:this.$={type1:a[s-2],type2:a[s],lineType:a[s-1]};break;case 49:this.$={type1:"none",type2:a[s],lineType:a[s-1]};break;case 50:this.$={type1:a[s-1],type2:"none",lineType:a[s]};break;case 51:this.$={type1:"none",type2:"none",lineType:a[s]};break;case 52:this.$=r.relationType.AGGREGATION;break;case 53:this.$=r.relationType.EXTENSION;break;case 54:this.$=r.relationType.COMPOSITION;break;case 55:this.$=r.relationType.DEPENDENCY;break;case 56:this.$=r.lineType.LINE;break;case 57:this.$=r.lineType.DOTTED_LINE;break;case 58:case 64:this.$=a[s-2],r.setClickEvent(a[s-1],a[s]);break;case 59:case 65:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 60:case 68:this.$=a[s-2],r.setLink(a[s-1],a[s]);break;case 61:case 69:this.$=a[s-3],r.setLink(a[s-2],a[s-1],a[s]);break;case 62:case 70:this.$=a[s-3],r.setLink(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 63:case 71:this.$=a[s-4],r.setLink(a[s-3],a[s-2],a[s]),r.setTooltip(a[s-3],a[s-1]);break;case 66:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 67:this.$=a[s-4],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setTooltip(a[s-3],a[s]);break;case 72:r.setCssClass(a[s-1],a[s])}},table:[{3:1,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o},{1:[3]},{1:[2,1]},{1:[2,2]},{3:13,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o},{1:[2,8]},t(s,[2,4]),t(s,[2,5]),t(s,[2,6]),t(s,[2,7]),{13:14,19:[1,15]},{15:[1,16]},{19:[2,11]},{1:[2,3]},{14:17,16:[1,18],21:c},t([16,21],[2,12]),{5:29,6:28,7:e,8:n,9:r,10:i,12:10,18:a,23:20,25:21,26:30,27:39,28:40,30:22,32:23,33:24,34:25,35:26,36:27,37:u,42:l,44:h,45:f,56:d,57:p,59:y,63:g,77:m,78:v,79:b,80:_},{15:[1,45]},{17:46,20:[1,47]},{15:[2,14]},{24:[1,48]},{15:[1,49],24:[2,16]},t(x,[2,24],{31:[1,50]}),t(x,[2,26]),t(x,[2,27]),t(x,[2,28]),t(x,[2,29]),t(x,[2,30]),t(x,[2,31]),t(x,[2,32]),t(x,[2,40],{46:51,48:54,49:55,31:[1,53],47:[1,52],50:w,51:k,52:T,53:E,54:C,55:S}),{26:62,27:39,28:40,77:m,78:v,79:b,80:_},t(x,[2,42]),t(x,[2,43]),{27:63,77:m,78:v,79:b},{26:64,27:39,28:40,77:m,78:v,79:b,80:_},{26:65,27:39,28:40,77:m,78:v,79:b,80:_},{26:66,27:39,28:40,77:m,78:v,79:b,80:_},{47:[1,67]},t(A,[2,19],{27:39,28:40,26:68,29:[1,69],77:m,78:v,79:b,80:_}),t(A,[2,20],{29:[1,70]}),t(M,[2,86]),t(M,[2,87]),t(M,[2,88]),t([15,24,29,31,38,39,47,50,51,52,53,54,55,60,62],[2,89]),t(N,[2,9]),{14:71,21:c},{21:[2,13]},{1:[2,15]},{5:29,6:28,7:e,8:n,9:r,10:i,12:10,18:a,23:72,24:[2,17],25:21,26:30,27:39,28:40,30:22,32:23,33:24,34:25,35:26,36:27,37:u,42:l,44:h,45:f,56:d,57:p,59:y,63:g,77:m,78:v,79:b,80:_},t(x,[2,25]),{26:73,27:39,28:40,47:[1,74],77:m,78:v,79:b,80:_},{46:75,48:54,49:55,50:w,51:k,52:T,53:E,54:C,55:S},t(x,[2,41]),{49:76,54:C,55:S},t(D,[2,51],{48:77,50:w,51:k,52:T,53:E}),t(O,[2,52]),t(O,[2,53]),t(O,[2,54]),t(O,[2,55]),t(B,[2,56]),t(B,[2,57]),t(x,[2,33],{38:[1,78],39:[1,79]}),{43:[1,80]},{47:[1,81]},{47:[1,82]},{60:[1,83],62:[1,84]},{27:85,77:m,78:v,79:b},t(A,[2,21]),t(A,[2,22]),t(A,[2,23]),{15:[1,86]},{24:[2,18]},t(L,[2,44]),{26:87,27:39,28:40,77:m,78:v,79:b,80:_},{26:88,27:39,28:40,47:[1,89],77:m,78:v,79:b,80:_},t(D,[2,50],{48:90,50:w,51:k,52:T,53:E}),t(D,[2,49]),{27:91,77:m,78:v,79:b},{40:92,44:I},{26:94,27:39,28:40,77:m,78:v,79:b,80:_},t(x,[2,58],{47:[1,95]}),t(x,[2,60],{47:[1,97],58:[1,96]}),t(x,[2,64],{47:[1,98],61:[1,99]}),t(x,[2,68],{47:[1,101],58:[1,100]}),t(x,[2,72]),t(N,[2,10]),t(L,[2,46]),t(L,[2,45]),{26:102,27:39,28:40,77:m,78:v,79:b,80:_},t(D,[2,48]),t(x,[2,34],{39:[1,103]}),{41:[1,104]},{40:105,41:[2,38],44:I},t(x,[2,37]),t(x,[2,59]),t(x,[2,61]),t(x,[2,62],{58:[1,106]}),t(x,[2,65]),t(x,[2,66],{47:[1,107]}),t(x,[2,69]),t(x,[2,70],{58:[1,108]}),t(L,[2,47]),{40:109,44:I},t(x,[2,35]),{41:[2,39]},t(x,[2,63]),t(x,[2,67]),t(x,[2,71]),{41:[1,110]},t(x,[2,36])],defaultActions:{2:[2,1],3:[2,2],5:[2,8],12:[2,11],13:[2,3],19:[2,14],47:[2,13],48:[2,15],72:[2,18],105:[2,39]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},F={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),18;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 10;case 5:return this.begin("type_directive"),19;case 6:return this.popState(),this.begin("arg_directive"),16;case 7:return this.popState(),this.popState(),21;case 8:return 20;case 9:case 10:case 12:case 19:break;case 11:return 15;case 13:case 14:return 22;case 15:return this.begin("struct"),39;case 16:return"EOF_IN_STRUCT";case 17:return"OPEN_IN_STRUCT";case 18:return this.popState(),41;case 20:return"MEMBER";case 21:return 37;case 22:return 63;case 23:return 56;case 24:return 57;case 25:return 59;case 26:return 42;case 27:return 43;case 28:this.begin("generic");break;case 29:case 32:case 35:case 38:case 41:case 44:this.popState();break;case 30:return"GENERICTYPE";case 31:this.begin("string");break;case 33:return"STR";case 34:this.begin("bqstring");break;case 36:return"BQUOTE_STR";case 37:this.begin("href");break;case 39:return 62;case 40:this.begin("callback_name");break;case 42:this.popState(),this.begin("callback_args");break;case 43:return 60;case 45:return 61;case 46:case 47:case 48:case 49:return 58;case 50:case 51:return 51;case 52:case 53:return 53;case 54:return 52;case 55:return 50;case 56:return 54;case 57:return 55;case 58:return 31;case 59:return 38;case 60:return 75;case 61:return"DOT";case 62:return"PLUS";case 63:return 72;case 64:case 65:return"EQUALS";case 66:return 79;case 67:return"PUNCTUATION";case 68:return 78;case 69:return 77;case 70:return 74;case 71:return 24}},rules:[/^(?:%%\{)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:[{])/,/^(?:$)/,/^(?:[{])/,/^(?:[}])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:class\b)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:[~])/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[`])/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:$)/],conditions:{arg_directive:{rules:[7,8],inclusive:!1},type_directive:{rules:[6,7],inclusive:!1},open_directive:{rules:[5],inclusive:!1},callback_args:{rules:[44,45],inclusive:!1},callback_name:{rules:[41,42,43],inclusive:!1},href:{rules:[38,39],inclusive:!1},struct:{rules:[16,17,18,19,20],inclusive:!1},generic:{rules:[29,30],inclusive:!1},bqstring:{rules:[35,36],inclusive:!1},string:{rules:[32,33],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,12,13,14,15,21,22,23,24,25,26,27,28,31,34,37,40,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71],inclusive:!0}}};function P(){this.yy={}}return R.lexer=F,P.prototype=R,R.Parser=P,new P}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8218).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},5890:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,23,41],i=[1,17],a=[1,20],o=[1,25],s=[1,26],c=[1,27],u=[1,28],l=[1,37],h=[23,38,39],f=[4,6,9,11,23,41],d=[34,35,36,37],p=[22,29],y=[1,55],g={trace:function(){},yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,entityName:17,relSpec:18,role:19,BLOCK_START:20,attributes:21,BLOCK_STOP:22,ALPHANUM:23,attribute:24,attributeType:25,attributeName:26,attributeKeyType:27,attributeComment:28,ATTRIBUTE_WORD:29,ATTRIBUTE_KEY:30,COMMENT:31,cardinality:32,relType:33,ZERO_OR_ONE:34,ZERO_OR_MORE:35,ONE_OR_MORE:36,ONLY_ONE:37,NON_IDENTIFYING:38,IDENTIFYING:39,WORD:40,open_directive:41,type_directive:42,arg_directive:43,close_directive:44,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",20:"BLOCK_START",22:"BLOCK_STOP",23:"ALPHANUM",29:"ATTRIBUTE_WORD",30:"ATTRIBUTE_KEY",31:"COMMENT",34:"ZERO_OR_ONE",35:"ZERO_OR_MORE",36:"ONE_OR_MORE",37:"ONLY_ONE",38:"NON_IDENTIFYING",39:"IDENTIFYING",40:"WORD",41:"open_directive",42:"type_directive",43:"arg_directive",44:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,5],[10,4],[10,3],[10,1],[17,1],[21,1],[21,2],[24,2],[24,3],[24,3],[24,4],[25,1],[26,1],[27,1],[28,1],[18,3],[32,1],[32,1],[32,1],[32,1],[33,1],[33,1],[19,1],[19,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:break;case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:case 16:case 23:case 24:case 25:case 35:this.$=a[s];break;case 12:r.addEntity(a[s-4]),r.addEntity(a[s-2]),r.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 13:r.addEntity(a[s-3]),r.addAttributes(a[s-3],a[s-1]);break;case 14:r.addEntity(a[s-2]);break;case 15:r.addEntity(a[s]);break;case 17:this.$=[a[s]];break;case 18:a[s].push(a[s-1]),this.$=a[s];break;case 19:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 20:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeKeyType:a[s]};break;case 21:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeComment:a[s]};break;case 22:this.$={attributeType:a[s-3],attributeName:a[s-2],attributeKeyType:a[s-1],attributeComment:a[s]};break;case 26:case 34:this.$=a[s].replace(/"/g,"");break;case 27:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 28:this.$=r.Cardinality.ZERO_OR_ONE;break;case 29:this.$=r.Cardinality.ZERO_OR_MORE;break;case 30:this.$=r.Cardinality.ONE_OR_MORE;break;case 31:this.$=r.Cardinality.ONLY_ONE;break;case 32:this.$=r.Identification.NON_IDENTIFYING;break;case 33:this.$=r.Identification.IDENTIFYING;break;case 36:r.parseDirective("%%{","open_directive");break;case 37:r.parseDirective(a[s],"type_directive");break;case 38:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 39:r.parseDirective("}%%","close_directive","er")}},table:[{3:1,4:e,7:3,12:4,41:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,41:n},{13:8,42:[1,9]},{42:[2,36]},{6:[1,10],7:15,8:11,9:[1,12],10:13,11:[1,14],12:4,17:16,23:i,41:n},{1:[2,2]},{14:18,15:[1,19],44:a},t([15,44],[2,37]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:15,10:21,12:4,17:16,23:i,41:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,15],{18:22,32:24,20:[1,23],34:o,35:s,36:c,37:u}),t([6,9,11,15,20,23,34,35,36,37,41],[2,16]),{11:[1,29]},{16:30,43:[1,31]},{11:[2,39]},t(r,[2,5]),{17:32,23:i},{21:33,22:[1,34],24:35,25:36,29:l},{33:38,38:[1,39],39:[1,40]},t(h,[2,28]),t(h,[2,29]),t(h,[2,30]),t(h,[2,31]),t(f,[2,9]),{14:41,44:a},{44:[2,38]},{15:[1,42]},{22:[1,43]},t(r,[2,14]),{21:44,22:[2,17],24:35,25:36,29:l},{26:45,29:[1,46]},{29:[2,23]},{32:47,34:o,35:s,36:c,37:u},t(d,[2,32]),t(d,[2,33]),{11:[1,48]},{19:49,23:[1,51],40:[1,50]},t(r,[2,13]),{22:[2,18]},t(p,[2,19],{27:52,28:53,30:[1,54],31:y}),t([22,29,30,31],[2,24]),{23:[2,27]},t(f,[2,10]),t(r,[2,12]),t(r,[2,34]),t(r,[2,35]),t(p,[2,20],{28:56,31:y}),t(p,[2,21]),t([22,29,31],[2,25]),t(p,[2,26]),t(p,[2,22])],defaultActions:{5:[2,36],7:[2,2],20:[2,39],31:[2,38],37:[2,23],44:[2,18],47:[2,27]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},m={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),41;case 1:return this.begin("type_directive"),42;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),44;case 4:return 43;case 5:case 6:case 8:case 13:case 17:break;case 7:return 11;case 9:return 9;case 10:return 40;case 11:return 4;case 12:return this.begin("block"),20;case 14:return 30;case 15:return 29;case 16:return 31;case 18:return this.popState(),22;case 19:case 32:return e.yytext[0];case 20:case 24:return 34;case 21:case 25:return 35;case 22:case 26:return 36;case 23:return 37;case 27:case 29:case 30:return 38;case 28:return 39;case 31:return 23;case 33:return 6}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:\s+)/i,/^(?:(?:PK)|(?:FK))/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:"[^"]*")/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\|o\b)/i,/^(?:\}o\b)/i,/^(?:\}\|)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},block:{rules:[13,14,15,16,17,18,19],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,20,21,22,23,24,25,26,27,28,29,30,31,32,33],inclusive:!0}}};function v(){this.yy={}}return g.lexer=m,v.prototype=g,g.Parser=v,new v}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8009).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3602:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,9],n=[1,7],r=[1,6],i=[1,8],a=[1,20,21,22,23,38,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],o=[2,10],s=[1,20],c=[1,21],u=[1,22],l=[1,23],h=[1,30],f=[1,59],d=[1,45],p=[1,49],y=[1,33],g=[1,34],m=[1,35],v=[1,36],b=[1,37],_=[1,53],x=[1,60],w=[1,48],k=[1,50],T=[1,52],E=[1,56],C=[1,57],S=[1,38],A=[1,39],M=[1,40],N=[1,41],D=[1,58],O=[1,47],B=[1,51],L=[1,54],I=[1,55],R=[1,46],F=[1,63],P=[1,68],j=[1,20,21,22,23,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],Y=[1,72],z=[1,71],U=[1,73],q=[20,21,23,74,75],H=[1,94],$=[1,99],W=[1,102],V=[1,103],G=[1,96],X=[1,101],Z=[1,104],Q=[1,97],K=[1,109],J=[1,108],tt=[1,98],et=[1,100],nt=[1,105],rt=[1,106],it=[1,107],at=[1,110],ot=[20,21,22,23,74,75],st=[20,21,22,23,48,74,75],ct=[20,21,22,23,40,47,48,50,52,54,56,58,59,60,62,64,66,67,69,74,75,84,88,98,99,102,104,105,115,116,117,118,119,120],ut=[20,21,23],lt=[20,21,23,47,59,60,74,75,84,88,98,99,102,104,105,115,116,117,118,119,120],ht=[1,12,20,21,22,23,24,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],ft=[47,59,60,84,88,98,99,102,104,105,115,116,117,118,119,120],dt=[1,143],pt=[1,151],yt=[1,152],gt=[1,153],mt=[1,154],vt=[1,138],bt=[1,139],_t=[1,135],xt=[1,146],wt=[1,147],kt=[1,148],Tt=[1,149],Et=[1,150],Ct=[1,155],St=[1,156],At=[1,141],Mt=[1,144],Nt=[1,140],Dt=[1,137],Ot=[20,21,22,23,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],Bt=[1,159],Lt=[20,21,22,23,26,47,59,60,84,98,99,102,104,105,115,116,117,118,119,120],It=[20,21,22,23,24,26,38,40,41,42,47,51,53,55,57,59,60,61,63,65,66,68,70,74,75,79,80,81,82,83,84,85,88,98,99,102,104,105,106,107,115,116,117,118,119,120],Rt=[12,21,22,24],Ft=[22,99],Pt=[1,242],jt=[1,237],Yt=[1,238],zt=[1,246],Ut=[1,243],qt=[1,240],Ht=[1,239],$t=[1,241],Wt=[1,244],Vt=[1,245],Gt=[1,247],Xt=[1,265],Zt=[20,21,23,99],Qt=[20,21,22,23,59,60,79,95,98,99,102,103,104,105,106],Kt={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,directive:5,openDirective:6,typeDirective:7,closeDirective:8,separator:9,":":10,argDirective:11,open_directive:12,type_directive:13,arg_directive:14,close_directive:15,graphConfig:16,document:17,line:18,statement:19,SEMI:20,NEWLINE:21,SPACE:22,EOF:23,GRAPH:24,NODIR:25,DIR:26,FirstStmtSeperator:27,ending:28,endToken:29,spaceList:30,spaceListNewline:31,verticeStatement:32,styleStatement:33,linkStyleStatement:34,classDefStatement:35,classStatement:36,clickStatement:37,subgraph:38,text:39,SQS:40,SQE:41,end:42,direction:43,link:44,node:45,vertex:46,AMP:47,STYLE_SEPARATOR:48,idString:49,PS:50,PE:51,"(-":52,"-)":53,STADIUMSTART:54,STADIUMEND:55,SUBROUTINESTART:56,SUBROUTINEEND:57,VERTEX_WITH_PROPS_START:58,ALPHA:59,COLON:60,PIPE:61,CYLINDERSTART:62,CYLINDEREND:63,DIAMOND_START:64,DIAMOND_STOP:65,TAGEND:66,TRAPSTART:67,TRAPEND:68,INVTRAPSTART:69,INVTRAPEND:70,linkStatement:71,arrowText:72,TESTSTR:73,START_LINK:74,LINK:75,textToken:76,STR:77,keywords:78,STYLE:79,LINKSTYLE:80,CLASSDEF:81,CLASS:82,CLICK:83,DOWN:84,UP:85,textNoTags:86,textNoTagsToken:87,DEFAULT:88,stylesOpt:89,alphaNum:90,CALLBACKNAME:91,CALLBACKARGS:92,HREF:93,LINK_TARGET:94,HEX:95,numList:96,INTERPOLATE:97,NUM:98,COMMA:99,style:100,styleComponent:101,MINUS:102,UNIT:103,BRKT:104,DOT:105,PCT:106,TAGSTART:107,alphaNumToken:108,idStringToken:109,alphaNumStatement:110,direction_tb:111,direction_bt:112,direction_rl:113,direction_lr:114,PUNCTUATION:115,UNICODE_TEXT:116,PLUS:117,EQUALS:118,MULT:119,UNDERSCORE:120,graphCodeTokens:121,ARROW_CROSS:122,ARROW_POINT:123,ARROW_CIRCLE:124,ARROW_OPEN:125,QUOTE:126,$accept:0,$end:1},terminals_:{2:"error",10:":",12:"open_directive",13:"type_directive",14:"arg_directive",15:"close_directive",20:"SEMI",21:"NEWLINE",22:"SPACE",23:"EOF",24:"GRAPH",25:"NODIR",26:"DIR",38:"subgraph",40:"SQS",41:"SQE",42:"end",47:"AMP",48:"STYLE_SEPARATOR",50:"PS",51:"PE",52:"(-",53:"-)",54:"STADIUMSTART",55:"STADIUMEND",56:"SUBROUTINESTART",57:"SUBROUTINEEND",58:"VERTEX_WITH_PROPS_START",59:"ALPHA",60:"COLON",61:"PIPE",62:"CYLINDERSTART",63:"CYLINDEREND",64:"DIAMOND_START",65:"DIAMOND_STOP",66:"TAGEND",67:"TRAPSTART",68:"TRAPEND",69:"INVTRAPSTART",70:"INVTRAPEND",73:"TESTSTR",74:"START_LINK",75:"LINK",77:"STR",79:"STYLE",80:"LINKSTYLE",81:"CLASSDEF",82:"CLASS",83:"CLICK",84:"DOWN",85:"UP",88:"DEFAULT",91:"CALLBACKNAME",92:"CALLBACKARGS",93:"HREF",94:"LINK_TARGET",95:"HEX",97:"INTERPOLATE",98:"NUM",99:"COMMA",102:"MINUS",103:"UNIT",104:"BRKT",105:"DOT",106:"PCT",107:"TAGSTART",111:"direction_tb",112:"direction_bt",113:"direction_rl",114:"direction_lr",115:"PUNCTUATION",116:"UNICODE_TEXT",117:"PLUS",118:"EQUALS",119:"MULT",120:"UNDERSCORE",122:"ARROW_CROSS",123:"ARROW_POINT",124:"ARROW_CIRCLE",125:"ARROW_OPEN",126:"QUOTE"},productions_:[0,[3,1],[3,2],[5,4],[5,6],[6,1],[7,1],[11,1],[8,1],[4,2],[17,0],[17,2],[18,1],[18,1],[18,1],[18,1],[18,1],[16,2],[16,2],[16,2],[16,3],[28,2],[28,1],[29,1],[29,1],[29,1],[27,1],[27,1],[27,2],[31,2],[31,2],[31,1],[31,1],[30,2],[30,1],[19,2],[19,2],[19,2],[19,2],[19,2],[19,2],[19,9],[19,6],[19,4],[19,1],[9,1],[9,1],[9,1],[32,3],[32,4],[32,2],[32,1],[45,1],[45,5],[45,3],[46,4],[46,6],[46,4],[46,4],[46,4],[46,8],[46,4],[46,4],[46,4],[46,6],[46,4],[46,4],[46,4],[46,4],[46,4],[46,1],[44,2],[44,3],[44,3],[44,1],[44,3],[71,1],[72,3],[39,1],[39,2],[39,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[86,1],[86,2],[35,5],[35,5],[36,5],[37,2],[37,4],[37,3],[37,5],[37,2],[37,4],[37,4],[37,6],[37,2],[37,4],[37,2],[37,4],[37,4],[37,6],[33,5],[33,5],[34,5],[34,5],[34,9],[34,9],[34,7],[34,7],[96,1],[96,3],[89,1],[89,3],[100,1],[100,2],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[76,1],[76,1],[76,1],[76,1],[76,1],[76,1],[87,1],[87,1],[87,1],[87,1],[49,1],[49,2],[90,1],[90,2],[110,1],[110,1],[110,1],[110,1],[43,1],[43,1],[43,1],[43,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 5:r.parseDirective("%%{","open_directive");break;case 6:r.parseDirective(a[s],"type_directive");break;case 7:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 8:r.parseDirective("}%%","close_directive","flowchart");break;case 10:case 36:case 37:case 38:case 39:case 40:this.$=[];break;case 11:a[s]!==[]&&a[s-1].push(a[s]),this.$=a[s-1];break;case 12:case 78:case 80:case 92:case 148:case 150:case 151:case 74:case 146:this.$=a[s];break;case 19:r.setDirection("TB"),this.$="TB";break;case 20:r.setDirection(a[s-1]),this.$=a[s-1];break;case 35:this.$=a[s-1].nodes;break;case 41:this.$=r.addSubGraph(a[s-6],a[s-1],a[s-4]);break;case 42:this.$=r.addSubGraph(a[s-3],a[s-1],a[s-3]);break;case 43:this.$=r.addSubGraph(void 0,a[s-1],void 0);break;case 48:r.addLink(a[s-2].stmt,a[s],a[s-1]),this.$={stmt:a[s],nodes:a[s].concat(a[s-2].nodes)};break;case 49:r.addLink(a[s-3].stmt,a[s-1],a[s-2]),this.$={stmt:a[s-1],nodes:a[s-1].concat(a[s-3].nodes)};break;case 50:this.$={stmt:a[s-1],nodes:a[s-1]};break;case 51:this.$={stmt:a[s],nodes:a[s]};break;case 52:case 119:case 121:this.$=[a[s]];break;case 53:this.$=a[s-4].concat(a[s]);break;case 54:this.$=[a[s-2]],r.setClass(a[s-2],a[s]);break;case 55:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"square");break;case 56:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"circle");break;case 57:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"ellipse");break;case 58:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"stadium");break;case 59:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"subroutine");break;case 60:this.$=a[s-7],r.addVertex(a[s-7],a[s-1],"rect",void 0,void 0,void 0,Object.fromEntries([[a[s-5],a[s-3]]]));break;case 61:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"cylinder");break;case 62:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"round");break;case 63:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"diamond");break;case 64:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"hexagon");break;case 65:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"odd");break;case 66:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"trapezoid");break;case 67:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"inv_trapezoid");break;case 68:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_right");break;case 69:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_left");break;case 70:this.$=a[s],r.addVertex(a[s]);break;case 71:a[s-1].text=a[s],this.$=a[s-1];break;case 72:case 73:a[s-2].text=a[s-1],this.$=a[s-2];break;case 75:var c=r.destructLink(a[s],a[s-2]);this.$={type:c.type,stroke:c.stroke,length:c.length,text:a[s-1]};break;case 76:c=r.destructLink(a[s]),this.$={type:c.type,stroke:c.stroke,length:c.length};break;case 77:this.$=a[s-1];break;case 79:case 93:case 149:case 147:this.$=a[s-1]+""+a[s];break;case 94:case 95:this.$=a[s-4],r.addClass(a[s-2],a[s]);break;case 96:this.$=a[s-4],r.setClass(a[s-2],a[s]);break;case 97:case 105:this.$=a[s-1],r.setClickEvent(a[s-1],a[s]);break;case 98:case 106:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 99:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 100:this.$=a[s-4],r.setClickEvent(a[s-4],a[s-3],a[s-2]),r.setTooltip(a[s-4],a[s]);break;case 101:case 107:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 102:case 108:this.$=a[s-3],r.setLink(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 103:case 109:this.$=a[s-3],r.setLink(a[s-3],a[s-2],a[s]);break;case 104:case 110:this.$=a[s-5],r.setLink(a[s-5],a[s-4],a[s]),r.setTooltip(a[s-5],a[s-2]);break;case 111:this.$=a[s-4],r.addVertex(a[s-2],void 0,void 0,a[s]);break;case 112:case 114:this.$=a[s-4],r.updateLink(a[s-2],a[s]);break;case 113:this.$=a[s-4],r.updateLink([a[s-2]],a[s]);break;case 115:this.$=a[s-8],r.updateLinkInterpolate([a[s-6]],a[s-2]),r.updateLink([a[s-6]],a[s]);break;case 116:this.$=a[s-8],r.updateLinkInterpolate(a[s-6],a[s-2]),r.updateLink(a[s-6],a[s]);break;case 117:this.$=a[s-6],r.updateLinkInterpolate([a[s-4]],a[s]);break;case 118:this.$=a[s-6],r.updateLinkInterpolate(a[s-4],a[s]);break;case 120:case 122:a[s-2].push(a[s]),this.$=a[s-2];break;case 124:this.$=a[s-1]+a[s];break;case 152:this.$="v";break;case 153:this.$="-";break;case 154:this.$={stmt:"dir",value:"TB"};break;case 155:this.$={stmt:"dir",value:"BT"};break;case 156:this.$={stmt:"dir",value:"RL"};break;case 157:this.$={stmt:"dir",value:"LR"}}},table:[{3:1,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},{1:[3]},{1:[2,1]},{3:10,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},t(a,o,{17:11}),{7:12,13:[1,13]},{16:14,21:n,22:r,24:i},{16:15,21:n,22:r,24:i},{25:[1,16],26:[1,17]},{13:[2,5]},{1:[2,2]},{1:[2,9],18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{8:61,10:[1,62],15:F},t([10,15],[2,6]),t(a,[2,17]),t(a,[2,18]),t(a,[2,19]),{20:[1,65],21:[1,66],22:P,27:64,30:67},t(j,[2,11]),t(j,[2,12]),t(j,[2,13]),t(j,[2,14]),t(j,[2,15]),t(j,[2,16]),{9:69,20:Y,21:z,23:U,44:70,71:74,74:[1,75],75:[1,76]},{9:77,20:Y,21:z,23:U},{9:78,20:Y,21:z,23:U},{9:79,20:Y,21:z,23:U},{9:80,20:Y,21:z,23:U},{9:81,20:Y,21:z,23:U},{9:83,20:Y,21:z,22:[1,82],23:U},t(j,[2,44]),t(q,[2,51],{30:84,22:P}),{22:[1,85]},{22:[1,86]},{22:[1,87]},{22:[1,88]},{26:H,47:$,59:W,60:V,77:[1,92],84:G,90:91,91:[1,89],93:[1,90],98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(j,[2,154]),t(j,[2,155]),t(j,[2,156]),t(j,[2,157]),t(ot,[2,52],{48:[1,111]}),t(st,[2,70],{109:123,40:[1,112],47:f,50:[1,113],52:[1,114],54:[1,115],56:[1,116],58:[1,117],59:d,60:p,62:[1,118],64:[1,119],66:[1,120],67:[1,121],69:[1,122],84:_,88:x,98:w,99:k,102:T,104:E,105:C,115:D,116:O,117:B,118:L,119:I,120:R}),t(ct,[2,146]),t(ct,[2,171]),t(ct,[2,172]),t(ct,[2,173]),t(ct,[2,174]),t(ct,[2,175]),t(ct,[2,176]),t(ct,[2,177]),t(ct,[2,178]),t(ct,[2,179]),t(ct,[2,180]),t(ct,[2,181]),t(ct,[2,182]),t(ct,[2,183]),t(ct,[2,184]),t(ct,[2,185]),t(ct,[2,186]),{9:124,20:Y,21:z,23:U},{11:125,14:[1,126]},t(ut,[2,8]),t(a,[2,20]),t(a,[2,26]),t(a,[2,27]),{21:[1,127]},t(lt,[2,34],{30:128,22:P}),t(j,[2,35]),{45:129,46:42,47:f,49:43,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},t(ht,[2,45]),t(ht,[2,46]),t(ht,[2,47]),t(ft,[2,74],{72:130,61:[1,132],73:[1,131]}),{22:dt,24:pt,26:yt,38:gt,39:133,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t([47,59,60,61,73,84,88,98,99,102,104,105,115,116,117,118,119,120],[2,76]),t(j,[2,36]),t(j,[2,37]),t(j,[2,38]),t(j,[2,39]),t(j,[2,40]),{22:dt,24:pt,26:yt,38:gt,39:157,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(Ot,o,{17:158}),t(q,[2,50],{47:Bt}),{26:H,47:$,59:W,60:V,84:G,90:160,95:[1,161],98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{88:[1,162],96:163,98:[1,164]},{26:H,47:$,59:W,60:V,84:G,88:[1,165],90:166,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{26:H,47:$,59:W,60:V,84:G,90:167,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,97],{22:[1,168],92:[1,169]}),t(ut,[2,101],{22:[1,170]}),t(ut,[2,105],{108:95,110:172,22:[1,171],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,107],{22:[1,173]}),t(Lt,[2,148]),t(Lt,[2,150]),t(Lt,[2,151]),t(Lt,[2,152]),t(Lt,[2,153]),t(It,[2,158]),t(It,[2,159]),t(It,[2,160]),t(It,[2,161]),t(It,[2,162]),t(It,[2,163]),t(It,[2,164]),t(It,[2,165]),t(It,[2,166]),t(It,[2,167]),t(It,[2,168]),t(It,[2,169]),t(It,[2,170]),{47:f,49:174,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},{22:dt,24:pt,26:yt,38:gt,39:175,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:177,42:mt,47:$,50:[1,176],59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:178,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:179,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:180,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{59:[1,181]},{22:dt,24:pt,26:yt,38:gt,39:182,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:183,42:mt,47:$,59:W,60:V,64:[1,184],66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:185,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:186,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:187,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ct,[2,147]),t(Rt,[2,3]),{8:188,15:F},{15:[2,7]},t(a,[2,28]),t(lt,[2,33]),t(q,[2,48],{30:189,22:P}),t(ft,[2,71],{22:[1,190]}),{22:[1,191]},{22:dt,24:pt,26:yt,38:gt,39:192,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,74:bt,75:[1,193],76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(It,[2,78]),t(It,[2,80]),t(It,[2,136]),t(It,[2,137]),t(It,[2,138]),t(It,[2,139]),t(It,[2,140]),t(It,[2,141]),t(It,[2,142]),t(It,[2,143]),t(It,[2,144]),t(It,[2,145]),t(It,[2,81]),t(It,[2,82]),t(It,[2,83]),t(It,[2,84]),t(It,[2,85]),t(It,[2,86]),t(It,[2,87]),t(It,[2,88]),t(It,[2,89]),t(It,[2,90]),t(It,[2,91]),{9:196,20:Y,21:z,22:dt,23:U,24:pt,26:yt,38:gt,40:[1,195],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,197],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{22:P,30:198},{22:[1,199],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:[1,200]},{22:[1,201]},{22:[1,202],99:[1,203]},t(Ft,[2,119]),{22:[1,204]},{22:[1,205],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:[1,206],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{77:[1,207]},t(ut,[2,99],{22:[1,208]}),{77:[1,209],94:[1,210]},{77:[1,211]},t(Lt,[2,149]),{77:[1,212],94:[1,213]},t(ot,[2,54],{109:123,47:f,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,115:D,116:O,117:B,118:L,119:I,120:R}),{22:dt,24:pt,26:yt,38:gt,41:[1,214],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:215,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,51:[1,216],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,53:[1,217],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,55:[1,218],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,57:[1,219],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{60:[1,220]},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,63:[1,221],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,65:[1,222],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:223,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,41:[1,224],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,68:[1,225],70:[1,226],74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,68:[1,228],70:[1,227],74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{9:229,20:Y,21:z,23:U},t(q,[2,49],{47:Bt}),t(ft,[2,73]),t(ft,[2,72]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,61:[1,230],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ft,[2,75]),t(It,[2,79]),{22:dt,24:pt,26:yt,38:gt,39:231,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(Ot,o,{17:232}),t(j,[2,43]),{46:233,47:f,49:43,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},{22:Pt,59:jt,60:Yt,79:zt,89:234,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:248,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:249,95:Ut,97:[1,250],98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:251,95:Ut,97:[1,252],98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{98:[1,253]},{22:Pt,59:jt,60:Yt,79:zt,89:254,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:255,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{26:H,47:$,59:W,60:V,84:G,90:256,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,98]),{77:[1,257]},t(ut,[2,102],{22:[1,258]}),t(ut,[2,103]),t(ut,[2,106]),t(ut,[2,108],{22:[1,259]}),t(ut,[2,109]),t(st,[2,55]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,51:[1,260],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,62]),t(st,[2,57]),t(st,[2,58]),t(st,[2,59]),{59:[1,261]},t(st,[2,61]),t(st,[2,63]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,65:[1,262],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,65]),t(st,[2,66]),t(st,[2,68]),t(st,[2,67]),t(st,[2,69]),t(Rt,[2,4]),t([22,47,59,60,84,88,98,99,102,104,105,115,116,117,118,119,120],[2,77]),{22:dt,24:pt,26:yt,38:gt,41:[1,263],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,264],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},t(ot,[2,53]),t(ut,[2,111],{99:Xt}),t(Zt,[2,121],{101:266,22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,102:Ht,103:$t,104:Wt,105:Vt,106:Gt}),t(Qt,[2,123]),t(Qt,[2,125]),t(Qt,[2,126]),t(Qt,[2,127]),t(Qt,[2,128]),t(Qt,[2,129]),t(Qt,[2,130]),t(Qt,[2,131]),t(Qt,[2,132]),t(Qt,[2,133]),t(Qt,[2,134]),t(Qt,[2,135]),t(ut,[2,112],{99:Xt}),t(ut,[2,113],{99:Xt}),{22:[1,267]},t(ut,[2,114],{99:Xt}),{22:[1,268]},t(Ft,[2,120]),t(ut,[2,94],{99:Xt}),t(ut,[2,95],{99:Xt}),t(ut,[2,96],{108:95,110:172,26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,100]),{94:[1,269]},{94:[1,270]},{51:[1,271]},{61:[1,272]},{65:[1,273]},{9:274,20:Y,21:z,23:U},t(j,[2,42]),{22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,100:275,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},t(Qt,[2,124]),{26:H,47:$,59:W,60:V,84:G,90:276,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{26:H,47:$,59:W,60:V,84:G,90:277,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,104]),t(ut,[2,110]),t(st,[2,56]),{22:dt,24:pt,26:yt,38:gt,39:278,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,64]),t(Ot,o,{17:279}),t(Zt,[2,122],{101:266,22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,102:Ht,103:$t,104:Wt,105:Vt,106:Gt}),t(ut,[2,117],{108:95,110:172,22:[1,280],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,118],{108:95,110:172,22:[1,281],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),{22:dt,24:pt,26:yt,38:gt,41:[1,282],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,283],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{22:Pt,59:jt,60:Yt,79:zt,89:284,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:285,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},t(st,[2,60]),t(j,[2,41]),t(ut,[2,115],{99:Xt}),t(ut,[2,116],{99:Xt})],defaultActions:{2:[2,1],9:[2,5],10:[2,2],126:[2,7]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},Jt={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),12;case 1:return this.begin("type_directive"),13;case 2:return this.popState(),this.begin("arg_directive"),10;case 3:return this.popState(),this.popState(),15;case 4:return 14;case 5:case 6:break;case 7:this.begin("string");break;case 8:case 17:case 20:case 23:case 26:this.popState();break;case 9:return"STR";case 10:return 79;case 11:return 88;case 12:return 80;case 13:return 97;case 14:return 81;case 15:return 82;case 16:this.begin("href");break;case 18:return 93;case 19:this.begin("callbackname");break;case 21:this.popState(),this.begin("callbackargs");break;case 22:return 91;case 24:return 92;case 25:this.begin("click");break;case 27:return 83;case 28:case 29:return t.lex.firstGraph()&&this.begin("dir"),24;case 30:return 38;case 31:return 42;case 32:case 33:case 34:case 35:return 94;case 36:return this.popState(),25;case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:return this.popState(),26;case 47:return 111;case 48:return 112;case 49:return 113;case 50:return 114;case 51:return 98;case 52:return 104;case 53:return 48;case 54:return 60;case 55:return 47;case 56:return 20;case 57:return 99;case 58:return 119;case 59:case 60:case 61:return 75;case 62:case 63:case 64:return 74;case 65:return 52;case 66:return 53;case 67:return 54;case 68:return 55;case 69:return 56;case 70:return 57;case 71:return 58;case 72:return 62;case 73:return 63;case 74:return 102;case 75:return 105;case 76:return 120;case 77:return 117;case 78:return 106;case 79:case 80:return 118;case 81:return 107;case 82:return 66;case 83:return 85;case 84:return"SEP";case 85:return 84;case 86:return 59;case 87:return 68;case 88:return 67;case 89:return 70;case 90:return 69;case 91:return 115;case 92:return 116;case 93:return 61;case 94:return 50;case 95:return 51;case 96:return 40;case 97:return 41;case 98:return 64;case 99:return 65;case 100:return 126;case 101:return 21;case 102:return 22;case 103:return 23}},rules:[/^(?:%%\{)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)[^\n]*)/,/^(?:[^\}]%%[^\n]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\[)/,/^(?:\]\))/,/^(?:\[\[)/,/^(?:\]\])/,/^(?:\[\|)/,/^(?:\[\()/,/^(?:\)\])/,/^(?:-)/,/^(?:\.)/,/^(?:[\_])/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:[A-Za-z]+)/,/^(?:\\\])/,/^(?:\[\/)/,/^(?:\/\])/,/^(?:\[\\)/,/^(?:[!"#$%&'*+,-.`?\\_/])/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[23,24],inclusive:!1},callbackname:{rules:[20,21,22],inclusive:!1},href:{rules:[17,18],inclusive:!1},click:{rules:[26,27],inclusive:!1},vertex:{rules:[],inclusive:!1},dir:{rules:[36,37,38,39,40,41,42,43,44,45,46],inclusive:!1},string:{rules:[8,9],inclusive:!1},INITIAL:{rules:[0,5,6,7,10,11,12,13,14,15,16,19,25,28,29,30,31,32,33,34,35,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103],inclusive:!0}}};function te(){this.yy={}}return Kt.lexer=Jt,te.prototype=Kt,Kt.Parser=te,new te}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(5354).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9959:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[7,9,11,12,13,14,15,16,17,18,19,20,22,29,34],i=[1,15],a=[1,16],o=[1,17],s=[1,18],c=[1,19],u=[1,20],l=[1,21],h=[1,22],f=[1,23],d=[1,25],p=[1,27],y=[1,30],g=[5,7,9,11,12,13,14,15,16,17,18,19,20,22,29,34],m={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,gantt:5,document:6,EOF:7,line:8,SPACE:9,statement:10,NL:11,dateFormat:12,inclusiveEndDates:13,topAxis:14,axisFormat:15,excludes:16,includes:17,todayMarker:18,title:19,section:20,clickStatement:21,taskTxt:22,taskData:23,openDirective:24,typeDirective:25,closeDirective:26,":":27,argDirective:28,click:29,callbackname:30,callbackargs:31,href:32,clickStatementDebug:33,open_directive:34,type_directive:35,arg_directive:36,close_directive:37,$accept:0,$end:1},terminals_:{2:"error",5:"gantt",7:"EOF",9:"SPACE",11:"NL",12:"dateFormat",13:"inclusiveEndDates",14:"topAxis",15:"axisFormat",16:"excludes",17:"includes",18:"todayMarker",19:"title",20:"section",22:"taskTxt",23:"taskData",27:":",29:"click",30:"callbackname",31:"callbackargs",32:"href",34:"open_directive",35:"type_directive",36:"arg_directive",37:"close_directive"},productions_:[0,[3,2],[3,3],[6,0],[6,2],[8,2],[8,1],[8,1],[8,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,1],[4,4],[4,6],[21,2],[21,3],[21,3],[21,4],[21,3],[21,4],[21,2],[33,2],[33,3],[33,3],[33,4],[33,3],[33,4],[33,2],[24,1],[25,1],[28,1],[26,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 2:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 9:r.setDateFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 10:r.enableInclusiveEndDates(),this.$=a[s].substr(18);break;case 11:r.TopAxis(),this.$=a[s].substr(8);break;case 12:r.setAxisFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 13:r.setExcludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 14:r.setIncludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 15:r.setTodayMarker(a[s].substr(12)),this.$=a[s].substr(12);break;case 16:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 17:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 19:r.addTask(a[s-1],a[s]),this.$="task";break;case 23:this.$=a[s-1],r.setClickEvent(a[s-1],a[s],null);break;case 24:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 25:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],null),r.setLink(a[s-2],a[s]);break;case 26:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setLink(a[s-3],a[s]);break;case 27:this.$=a[s-2],r.setClickEvent(a[s-2],a[s],null),r.setLink(a[s-2],a[s-1]);break;case 28:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-1],a[s]),r.setLink(a[s-3],a[s-2]);break;case 29:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 30:case 36:this.$=a[s-1]+" "+a[s];break;case 31:case 32:case 34:this.$=a[s-2]+" "+a[s-1]+" "+a[s];break;case 33:case 35:this.$=a[s-3]+" "+a[s-2]+" "+a[s-1]+" "+a[s];break;case 37:r.parseDirective("%%{","open_directive");break;case 38:r.parseDirective(a[s],"type_directive");break;case 39:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 40:r.parseDirective("}%%","close_directive","gantt")}},table:[{3:1,4:2,5:e,24:4,34:n},{1:[3]},{3:6,4:2,5:e,24:4,34:n},t(r,[2,3],{6:7}),{25:8,35:[1,9]},{35:[2,37]},{1:[2,1]},{4:26,7:[1,10],8:11,9:[1,12],10:13,11:[1,14],12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:h,20:f,21:24,22:d,24:4,29:p,34:n},{26:28,27:[1,29],37:y},t([27,37],[2,38]),t(r,[2,8],{1:[2,2]}),t(r,[2,4]),{4:26,10:31,12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:h,20:f,21:24,22:d,24:4,29:p,34:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,9]),t(r,[2,10]),t(r,[2,11]),t(r,[2,12]),t(r,[2,13]),t(r,[2,14]),t(r,[2,15]),t(r,[2,16]),t(r,[2,17]),t(r,[2,18]),{23:[1,32]},t(r,[2,20]),{30:[1,33],32:[1,34]},{11:[1,35]},{28:36,36:[1,37]},{11:[2,40]},t(r,[2,5]),t(r,[2,19]),t(r,[2,23],{31:[1,38],32:[1,39]}),t(r,[2,29],{30:[1,40]}),t(g,[2,21]),{26:41,37:y},{37:[2,39]},t(r,[2,24],{32:[1,42]}),t(r,[2,25]),t(r,[2,27],{31:[1,43]}),{11:[1,44]},t(r,[2,26]),t(r,[2,28]),t(g,[2,22])],defaultActions:{5:[2,37],6:[2,1],30:[2,40],37:[2,39]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},v={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),34;case 1:return this.begin("type_directive"),35;case 2:return this.popState(),this.begin("arg_directive"),27;case 3:return this.popState(),this.popState(),37;case 4:return 36;case 5:case 6:case 7:case 9:case 10:case 11:break;case 8:return 11;case 12:this.begin("href");break;case 13:case 16:case 19:case 22:this.popState();break;case 14:return 32;case 15:this.begin("callbackname");break;case 17:this.popState(),this.begin("callbackargs");break;case 18:return 30;case 20:return 31;case 21:this.begin("click");break;case 23:return 29;case 24:return 5;case 25:return 12;case 26:return 13;case 27:return 14;case 28:return 15;case 29:return 17;case 30:return 16;case 31:return 18;case 32:return"date";case 33:return 19;case 34:return 20;case 35:return 22;case 36:return 23;case 37:return 27;case 38:return 7;case 39:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[19,20],inclusive:!1},callbackname:{rules:[16,17,18],inclusive:!1},href:{rules:[13,14],inclusive:!1},click:{rules:[22,23],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,15,21,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],inclusive:!0}}};function b(){this.yy={}}return m.lexer=v,b.prototype=m,m.Parser=b,new b}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(6878).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},2553:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[2,3],n=[1,7],r=[7,12,15,17,19,20,21],i=[7,11,12,15,17,19,20,21],a=[2,20],o=[1,32],s={trace:function(){},yy:{},symbols_:{error:2,start:3,GG:4,":":5,document:6,EOF:7,DIR:8,options:9,body:10,OPT:11,NL:12,line:13,statement:14,COMMIT:15,commit_arg:16,BRANCH:17,ID:18,CHECKOUT:19,MERGE:20,RESET:21,reset_arg:22,STR:23,HEAD:24,reset_parents:25,CARET:26,$accept:0,$end:1},terminals_:{2:"error",4:"GG",5:":",7:"EOF",8:"DIR",11:"OPT",12:"NL",15:"COMMIT",17:"BRANCH",18:"ID",19:"CHECKOUT",20:"MERGE",21:"RESET",23:"STR",24:"HEAD",26:"CARET"},productions_:[0,[3,4],[3,5],[6,0],[6,2],[9,2],[9,1],[10,0],[10,2],[13,2],[13,1],[14,2],[14,2],[14,2],[14,2],[14,2],[16,0],[16,1],[22,2],[22,2],[25,0],[25,2]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 2:return r.setDirection(a[s-3]),a[s-1];case 4:r.setOptions(a[s-1]),this.$=a[s];break;case 5:a[s-1]+=a[s],this.$=a[s-1];break;case 7:this.$=[];break;case 8:a[s-1].push(a[s]),this.$=a[s-1];break;case 9:this.$=a[s-1];break;case 11:r.commit(a[s]);break;case 12:r.branch(a[s]);break;case 13:r.checkout(a[s]);break;case 14:r.merge(a[s]);break;case 15:r.reset(a[s]);break;case 16:this.$="";break;case 17:this.$=a[s];break;case 18:this.$=a[s-1]+":"+a[s];break;case 19:this.$=a[s-1]+":"+r.count,r.count=0;break;case 20:r.count=0;break;case 21:r.count+=1}},table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3],8:[1,4]},{6:5,7:e,9:6,12:n},{5:[1,8]},{7:[1,9]},t(r,[2,7],{10:10,11:[1,11]}),t(i,[2,6]),{6:12,7:e,9:6,12:n},{1:[2,1]},{7:[2,4],12:[1,15],13:13,14:14,15:[1,16],17:[1,17],19:[1,18],20:[1,19],21:[1,20]},t(i,[2,5]),{7:[1,21]},t(r,[2,8]),{12:[1,22]},t(r,[2,10]),{12:[2,16],16:23,23:[1,24]},{18:[1,25]},{18:[1,26]},{18:[1,27]},{18:[1,30],22:28,24:[1,29]},{1:[2,2]},t(r,[2,9]),{12:[2,11]},{12:[2,17]},{12:[2,12]},{12:[2,13]},{12:[2,14]},{12:[2,15]},{12:a,25:31,26:o},{12:a,25:33,26:o},{12:[2,18]},{12:a,25:34,26:o},{12:[2,19]},{12:[2,21]}],defaultActions:{9:[2,1],21:[2,2],23:[2,11],24:[2,17],25:[2,12],26:[2,13],27:[2,14],28:[2,15],31:[2,18],33:[2,19],34:[2,21]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},c={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 12;case 1:case 2:case 3:break;case 4:return 4;case 5:return 15;case 6:return 17;case 7:return 20;case 8:return 21;case 9:return 19;case 10:case 11:return 8;case 12:return 5;case 13:return 26;case 14:this.begin("options");break;case 15:case 18:this.popState();break;case 16:return 11;case 17:this.begin("string");break;case 19:return 23;case 20:return 18;case 21:return 7}},rules:[/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:gitGraph\b)/i,/^(?:commit\b)/i,/^(?:branch\b)/i,/^(?:merge\b)/i,/^(?:reset\b)/i,/^(?:checkout\b)/i,/^(?:LR\b)/i,/^(?:BT\b)/i,/^(?::)/i,/^(?:\^)/i,/^(?:options\r?\n)/i,/^(?:end\r?\n)/i,/^(?:[^\n]+\r?\n)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[a-zA-Z][-_\.a-zA-Z0-9]*[-_a-zA-Z0-9])/i,/^(?:$)/i],conditions:{options:{rules:[15,16],inclusive:!1},string:{rules:[18,19],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,20,21],inclusive:!0}}};function u(){this.yy={}}return s.lexer=c,u.prototype=s,s.Parser=u,new u}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8183).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},6765:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[6,9,10],n={trace:function(){},yy:{},symbols_:{error:2,start:3,info:4,document:5,EOF:6,line:7,statement:8,NL:9,showInfo:10,$accept:0,$end:1},terminals_:{2:"error",4:"info",6:"EOF",9:"NL",10:"showInfo"},productions_:[0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,1]],performAction:function(t,e,n,r,i,a,o){switch(a.length,i){case 1:return r;case 4:break;case 6:r.setInfo(!0)}},table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8]},{1:[2,1]},t(e,[2,3]),t(e,[2,4]),t(e,[2,5]),t(e,[2,6])],defaultActions:{4:[2,1]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},r={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 4;case 1:return 9;case 2:return"space";case 3:return 10;case 4:return 6;case 5:return"TXT"}},rules:[/^(?:info\b)/i,/^(?:[\s\n\r]+)/i,/^(?:[\s]+)/i,/^(?:showInfo\b)/i,/^(?:$)/i,/^(?:.)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5],inclusive:!0}}};function i(){this.yy={}}return n.lexer=r,i.prototype=n,n.Parser=i,new i}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1428).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},7062:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,4],n=[1,5],r=[1,6],i=[1,7],a=[1,9],o=[1,11,13,20,21,22,23],s=[2,5],c=[1,6,11,13,20,21,22,23],u=[20,21,22],l=[2,8],h=[1,18],f=[1,19],d=[1,24],p=[6,20,21,22,23],y={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,directive:5,PIE:6,document:7,showData:8,line:9,statement:10,txt:11,value:12,title:13,title_value:14,openDirective:15,typeDirective:16,closeDirective:17,":":18,argDirective:19,NEWLINE:20,";":21,EOF:22,open_directive:23,type_directive:24,arg_directive:25,close_directive:26,$accept:0,$end:1},terminals_:{2:"error",6:"PIE",8:"showData",11:"txt",12:"value",13:"title",14:"title_value",18:":",20:"NEWLINE",21:";",22:"EOF",23:"open_directive",24:"type_directive",25:"arg_directive",26:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,3],[7,0],[7,2],[9,2],[10,0],[10,2],[10,2],[10,1],[5,3],[5,5],[4,1],[4,1],[4,1],[15,1],[16,1],[19,1],[17,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setShowData(!0);break;case 7:this.$=a[s-1];break;case 9:r.addSection(a[s-1],r.cleanupValue(a[s]));break;case 10:this.$=a[s].trim(),r.setTitle(this.$);break;case 17:r.parseDirective("%%{","open_directive");break;case 18:r.parseDirective(a[s],"type_directive");break;case 19:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 20:r.parseDirective("}%%","close_directive","pie")}},table:[{3:1,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},{1:[3]},{3:10,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},{3:11,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},t(o,s,{7:12,8:[1,13]}),t(c,[2,14]),t(c,[2,15]),t(c,[2,16]),{16:14,24:[1,15]},{24:[2,17]},{1:[2,1]},{1:[2,2]},t(u,l,{15:8,9:16,10:17,5:20,1:[2,3],11:h,13:f,23:a}),t(o,s,{7:21}),{17:22,18:[1,23],26:d},t([18,26],[2,18]),t(o,[2,6]),{4:25,20:n,21:r,22:i},{12:[1,26]},{14:[1,27]},t(u,[2,11]),t(u,l,{15:8,9:16,10:17,5:20,1:[2,4],11:h,13:f,23:a}),t(p,[2,12]),{19:28,25:[1,29]},t(p,[2,20]),t(o,[2,7]),t(u,[2,9]),t(u,[2,10]),{17:30,26:d},{26:[2,19]},t(p,[2,13])],defaultActions:{9:[2,17],10:[2,1],11:[2,2],29:[2,19]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},g={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),23;case 1:return this.begin("type_directive"),24;case 2:return this.popState(),this.begin("arg_directive"),18;case 3:return this.popState(),this.popState(),26;case 4:return 25;case 5:case 6:case 8:case 9:break;case 7:return 20;case 10:return this.begin("title"),13;case 11:return this.popState(),"title_value";case 12:this.begin("string");break;case 13:this.popState();break;case 14:return"txt";case 15:return 6;case 16:return 8;case 17:return"value";case 18:return 22}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:[\s]+)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:pie\b)/i,/^(?:showData\b)/i,/^(?::[\s]*[\d]+(?:\.[\d]+)?)/i,/^(?:$)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},title:{rules:[11],inclusive:!1},string:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,12,15,16,17,18],inclusive:!0}}};function m(){this.yy={}}return y.lexer=g,m.prototype=y,y.Parser=m,new m}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(4551).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3176:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[1,17],i=[2,10],a=[1,21],o=[1,22],s=[1,23],c=[1,24],u=[1,25],l=[1,26],h=[1,19],f=[1,27],d=[1,28],p=[1,31],y=[66,67],g=[5,8,14,35,36,37,38,39,40,48,55,57,66,67],m=[5,6,8,14,35,36,37,38,39,40,48,66,67],v=[1,51],b=[1,52],_=[1,53],x=[1,54],w=[1,55],k=[1,56],T=[1,57],E=[57,58],C=[1,69],S=[1,65],A=[1,66],M=[1,67],N=[1,68],D=[1,70],O=[1,74],B=[1,75],L=[1,72],I=[1,73],R=[5,8,14,35,36,37,38,39,40,48,66,67],F={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,openDirective:9,typeDirective:10,closeDirective:11,":":12,argDirective:13,open_directive:14,type_directive:15,arg_directive:16,close_directive:17,requirementDef:18,elementDef:19,relationshipDef:20,requirementType:21,requirementName:22,STRUCT_START:23,requirementBody:24,ID:25,COLONSEP:26,id:27,TEXT:28,text:29,RISK:30,riskLevel:31,VERIFYMTHD:32,verifyType:33,STRUCT_STOP:34,REQUIREMENT:35,FUNCTIONAL_REQUIREMENT:36,INTERFACE_REQUIREMENT:37,PERFORMANCE_REQUIREMENT:38,PHYSICAL_REQUIREMENT:39,DESIGN_CONSTRAINT:40,LOW_RISK:41,MED_RISK:42,HIGH_RISK:43,VERIFY_ANALYSIS:44,VERIFY_DEMONSTRATION:45,VERIFY_INSPECTION:46,VERIFY_TEST:47,ELEMENT:48,elementName:49,elementBody:50,TYPE:51,type:52,DOCREF:53,ref:54,END_ARROW_L:55,relationship:56,LINE:57,END_ARROW_R:58,CONTAINS:59,COPIES:60,DERIVES:61,SATISFIES:62,VERIFIES:63,REFINES:64,TRACES:65,unqString:66,qString:67,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",12:":",14:"open_directive",15:"type_directive",16:"arg_directive",17:"close_directive",23:"STRUCT_START",25:"ID",26:"COLONSEP",28:"TEXT",30:"RISK",32:"VERIFYMTHD",34:"STRUCT_STOP",35:"REQUIREMENT",36:"FUNCTIONAL_REQUIREMENT",37:"INTERFACE_REQUIREMENT",38:"PERFORMANCE_REQUIREMENT",39:"PHYSICAL_REQUIREMENT",40:"DESIGN_CONSTRAINT",41:"LOW_RISK",42:"MED_RISK",43:"HIGH_RISK",44:"VERIFY_ANALYSIS",45:"VERIFY_DEMONSTRATION",46:"VERIFY_INSPECTION",47:"VERIFY_TEST",48:"ELEMENT",51:"TYPE",53:"DOCREF",55:"END_ARROW_L",57:"LINE",58:"END_ARROW_R",59:"CONTAINS",60:"COPIES",61:"DERIVES",62:"SATISFIES",63:"VERIFIES",64:"REFINES",65:"TRACES",66:"unqString",67:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,3],[4,5],[9,1],[10,1],[13,1],[11,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[18,5],[24,5],[24,5],[24,5],[24,5],[24,2],[24,1],[21,1],[21,1],[21,1],[21,1],[21,1],[21,1],[31,1],[31,1],[31,1],[33,1],[33,1],[33,1],[33,1],[19,5],[50,5],[50,5],[50,2],[50,1],[20,5],[20,5],[56,1],[56,1],[56,1],[56,1],[56,1],[56,1],[56,1],[22,1],[22,1],[27,1],[27,1],[29,1],[29,1],[49,1],[49,1],[52,1],[52,1],[54,1],[54,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 6:r.parseDirective("%%{","open_directive");break;case 7:r.parseDirective(a[s],"type_directive");break;case 8:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 9:r.parseDirective("}%%","close_directive","pie");break;case 10:this.$=[];break;case 16:r.addRequirement(a[s-3],a[s-4]);break;case 17:r.setNewReqId(a[s-2]);break;case 18:r.setNewReqText(a[s-2]);break;case 19:r.setNewReqRisk(a[s-2]);break;case 20:r.setNewReqVerifyMethod(a[s-2]);break;case 23:this.$=r.RequirementType.REQUIREMENT;break;case 24:this.$=r.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 25:this.$=r.RequirementType.INTERFACE_REQUIREMENT;break;case 26:this.$=r.RequirementType.PERFORMANCE_REQUIREMENT;break;case 27:this.$=r.RequirementType.PHYSICAL_REQUIREMENT;break;case 28:this.$=r.RequirementType.DESIGN_CONSTRAINT;break;case 29:this.$=r.RiskLevel.LOW_RISK;break;case 30:this.$=r.RiskLevel.MED_RISK;break;case 31:this.$=r.RiskLevel.HIGH_RISK;break;case 32:this.$=r.VerifyType.VERIFY_ANALYSIS;break;case 33:this.$=r.VerifyType.VERIFY_DEMONSTRATION;break;case 34:this.$=r.VerifyType.VERIFY_INSPECTION;break;case 35:this.$=r.VerifyType.VERIFY_TEST;break;case 36:r.addElement(a[s-3]);break;case 37:r.setNewElementType(a[s-2]);break;case 38:r.setNewElementDocRef(a[s-2]);break;case 41:r.addRelationship(a[s-2],a[s],a[s-4]);break;case 42:r.addRelationship(a[s-2],a[s-4],a[s]);break;case 43:this.$=r.Relationships.CONTAINS;break;case 44:this.$=r.Relationships.COPIES;break;case 45:this.$=r.Relationships.DERIVES;break;case 46:this.$=r.Relationships.SATISFIES;break;case 47:this.$=r.Relationships.VERIFIES;break;case 48:this.$=r.Relationships.REFINES;break;case 49:this.$=r.Relationships.TRACES}},table:[{3:1,4:2,6:e,9:4,14:n},{1:[3]},{3:7,4:2,5:[1,6],6:e,9:4,14:n},{5:[1,8]},{10:9,15:[1,10]},{15:[2,6]},{3:11,4:2,6:e,9:4,14:n},{1:[2,2]},{4:16,5:r,7:12,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{11:29,12:[1,30],17:p},t([12,17],[2,7]),{1:[2,1]},{8:[1,32]},{4:16,5:r,7:33,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:34,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:35,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:36,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:37,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{22:38,66:[1,39],67:[1,40]},{49:41,66:[1,42],67:[1,43]},{55:[1,44],57:[1,45]},t(y,[2,23]),t(y,[2,24]),t(y,[2,25]),t(y,[2,26]),t(y,[2,27]),t(y,[2,28]),t(g,[2,52]),t(g,[2,53]),t(m,[2,4]),{13:46,16:[1,47]},t(m,[2,9]),{1:[2,3]},{8:[2,11]},{8:[2,12]},{8:[2,13]},{8:[2,14]},{8:[2,15]},{23:[1,48]},{23:[2,50]},{23:[2,51]},{23:[1,49]},{23:[2,56]},{23:[2,57]},{56:50,59:v,60:b,61:_,62:x,63:w,64:k,65:T},{56:58,59:v,60:b,61:_,62:x,63:w,64:k,65:T},{11:59,17:p},{17:[2,8]},{5:[1,60]},{5:[1,61]},{57:[1,62]},t(E,[2,43]),t(E,[2,44]),t(E,[2,45]),t(E,[2,46]),t(E,[2,47]),t(E,[2,48]),t(E,[2,49]),{58:[1,63]},t(m,[2,5]),{5:C,24:64,25:S,28:A,30:M,32:N,34:D},{5:O,34:B,50:71,51:L,53:I},{27:76,66:f,67:d},{27:77,66:f,67:d},t(R,[2,16]),{26:[1,78]},{26:[1,79]},{26:[1,80]},{26:[1,81]},{5:C,24:82,25:S,28:A,30:M,32:N,34:D},t(R,[2,22]),t(R,[2,36]),{26:[1,83]},{26:[1,84]},{5:O,34:B,50:85,51:L,53:I},t(R,[2,40]),t(R,[2,41]),t(R,[2,42]),{27:86,66:f,67:d},{29:87,66:[1,88],67:[1,89]},{31:90,41:[1,91],42:[1,92],43:[1,93]},{33:94,44:[1,95],45:[1,96],46:[1,97],47:[1,98]},t(R,[2,21]),{52:99,66:[1,100],67:[1,101]},{54:102,66:[1,103],67:[1,104]},t(R,[2,39]),{5:[1,105]},{5:[1,106]},{5:[2,54]},{5:[2,55]},{5:[1,107]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[1,108]},{5:[2,32]},{5:[2,33]},{5:[2,34]},{5:[2,35]},{5:[1,109]},{5:[2,58]},{5:[2,59]},{5:[1,110]},{5:[2,60]},{5:[2,61]},{5:C,24:111,25:S,28:A,30:M,32:N,34:D},{5:C,24:112,25:S,28:A,30:M,32:N,34:D},{5:C,24:113,25:S,28:A,30:M,32:N,34:D},{5:C,24:114,25:S,28:A,30:M,32:N,34:D},{5:O,34:B,50:115,51:L,53:I},{5:O,34:B,50:116,51:L,53:I},t(R,[2,17]),t(R,[2,18]),t(R,[2,19]),t(R,[2,20]),t(R,[2,37]),t(R,[2,38])],defaultActions:{5:[2,6],7:[2,2],11:[2,1],32:[2,3],33:[2,11],34:[2,12],35:[2,13],36:[2,14],37:[2,15],39:[2,50],40:[2,51],42:[2,56],43:[2,57],47:[2,8],88:[2,54],89:[2,55],91:[2,29],92:[2,30],93:[2,31],95:[2,32],96:[2,33],97:[2,34],98:[2,35],100:[2,58],101:[2,59],103:[2,60],104:[2,61]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},P={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),14;case 1:return this.begin("type_directive"),15;case 2:return this.popState(),this.begin("arg_directive"),12;case 3:return this.popState(),this.popState(),17;case 4:return 16;case 5:return 5;case 6:case 7:case 8:break;case 9:return 8;case 10:return 6;case 11:return 23;case 12:return 34;case 13:return 26;case 14:return 25;case 15:return 28;case 16:return 30;case 17:return 32;case 18:return 35;case 19:return 36;case 20:return 37;case 21:return 38;case 22:return 39;case 23:return 40;case 24:return 41;case 25:return 42;case 26:return 43;case 27:return 44;case 28:return 45;case 29:return 46;case 30:return 47;case 31:return 48;case 32:return 59;case 33:return 60;case 34:return 61;case 35:return 62;case 36:return 63;case 37:return 64;case 38:return 65;case 39:return 51;case 40:return 53;case 41:return 55;case 42:return 58;case 43:return 57;case 44:this.begin("string");break;case 45:this.popState();break;case 46:return"qString";case 47:return e.yytext=e.yytext.trim(),66}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:$)/i,/^(?:requirementDiagram\b)/i,/^(?:\{)/i,/^(?:\})/i,/^(?::)/i,/^(?:id\b)/i,/^(?:text\b)/i,/^(?:risk\b)/i,/^(?:verifyMethod\b)/i,/^(?:requirement\b)/i,/^(?:functionalRequirement\b)/i,/^(?:interfaceRequirement\b)/i,/^(?:performanceRequirement\b)/i,/^(?:physicalRequirement\b)/i,/^(?:designConstraint\b)/i,/^(?:low\b)/i,/^(?:medium\b)/i,/^(?:high\b)/i,/^(?:analysis\b)/i,/^(?:demonstration\b)/i,/^(?:inspection\b)/i,/^(?:test\b)/i,/^(?:element\b)/i,/^(?:contains\b)/i,/^(?:copies\b)/i,/^(?:derives\b)/i,/^(?:satisfies\b)/i,/^(?:verifies\b)/i,/^(?:refines\b)/i,/^(?:traces\b)/i,/^(?:type\b)/i,/^(?:docref\b)/i,/^(?:<-)/i,/^(?:->)/i,/^(?:-)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[\w][^\r\n\{\<\>\-\=]*)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},unqString:{rules:[],inclusive:!1},token:{rules:[],inclusive:!1},string:{rules:[45,46],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,47],inclusive:!0}}};function j(){this.yy={}}return F.lexer=P,j.prototype=F,F.Parser=j,new j}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8800).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},6876:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,18],u=[1,19],l=[1,21],h=[1,22],f=[1,23],d=[1,29],p=[1,30],y=[1,31],g=[1,32],m=[1,33],v=[1,34],b=[1,37],_=[1,38],x=[1,39],w=[1,40],k=[1,41],T=[1,42],E=[1,45],C=[1,4,5,16,20,22,23,24,30,32,33,34,35,36,38,40,41,42,46,47,48,49,57,67],S=[1,58],A=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,42,46,47,48,49,57,67],M=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,41,42,46,47,48,49,57,67],N=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,40,42,46,47,48,49,57,67],D=[55,56,57],O=[1,4,5,7,16,20,22,23,24,30,32,33,34,35,36,38,40,41,42,46,47,48,49,57,67],B={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,directive:6,SD:7,document:8,line:9,statement:10,openDirective:11,typeDirective:12,closeDirective:13,":":14,argDirective:15,participant:16,actor:17,AS:18,restOfLine:19,participant_actor:20,signal:21,autonumber:22,activate:23,deactivate:24,note_statement:25,links_statement:26,link_statement:27,properties_statement:28,details_statement:29,title:30,text2:31,loop:32,end:33,rect:34,opt:35,alt:36,else_sections:37,par:38,par_sections:39,and:40,else:41,note:42,placement:43,over:44,actor_pair:45,links:46,link:47,properties:48,details:49,spaceList:50,",":51,left_of:52,right_of:53,signaltype:54,"+":55,"-":56,ACTOR:57,SOLID_OPEN_ARROW:58,DOTTED_OPEN_ARROW:59,SOLID_ARROW:60,DOTTED_ARROW:61,SOLID_CROSS:62,DOTTED_CROSS:63,SOLID_POINT:64,DOTTED_POINT:65,TXT:66,open_directive:67,type_directive:68,arg_directive:69,close_directive:70,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",7:"SD",14:":",16:"participant",18:"AS",19:"restOfLine",20:"participant_actor",22:"autonumber",23:"activate",24:"deactivate",30:"title",32:"loop",33:"end",34:"rect",35:"opt",36:"alt",38:"par",40:"and",41:"else",42:"note",44:"over",46:"links",47:"link",48:"properties",49:"details",51:",",52:"left_of",53:"right_of",55:"+",56:"-",57:"ACTOR",58:"SOLID_OPEN_ARROW",59:"DOTTED_OPEN_ARROW",60:"SOLID_ARROW",61:"DOTTED_ARROW",62:"SOLID_CROSS",63:"DOTTED_CROSS",64:"SOLID_POINT",65:"DOTTED_POINT",66:"TXT",67:"open_directive",68:"type_directive",69:"arg_directive",70:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[6,4],[6,6],[10,5],[10,3],[10,5],[10,3],[10,2],[10,1],[10,3],[10,3],[10,2],[10,2],[10,2],[10,2],[10,2],[10,3],[10,4],[10,4],[10,4],[10,4],[10,4],[10,1],[39,1],[39,4],[37,1],[37,4],[25,4],[25,4],[26,3],[27,3],[28,3],[29,3],[50,2],[50,1],[45,3],[45,1],[43,1],[43,1],[21,5],[21,5],[21,4],[17,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[31,1],[11,1],[12,1],[15,1],[13,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.apply(a[s]),a[s];case 5:case 9:this.$=[];break;case 6:a[s-1].push(a[s]),this.$=a[s-1];break;case 7:case 8:case 45:this.$=a[s];break;case 12:a[s-3].type="addParticipant",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 13:a[s-1].type="addParticipant",this.$=a[s-1];break;case 14:a[s-3].type="addActor",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 15:a[s-1].type="addActor",this.$=a[s-1];break;case 17:r.enableSequenceNumbers();break;case 18:this.$={type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]};break;case 19:this.$={type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-1]};break;case 25:this.$=[{type:"setTitle",text:a[s-1]}];break;case 26:a[s-1].unshift({type:"loopStart",loopText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.LOOP_START}),a[s-1].push({type:"loopEnd",loopText:a[s-2],signalType:r.LINETYPE.LOOP_END}),this.$=a[s-1];break;case 27:a[s-1].unshift({type:"rectStart",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_START}),a[s-1].push({type:"rectEnd",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_END}),this.$=a[s-1];break;case 28:a[s-1].unshift({type:"optStart",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_START}),a[s-1].push({type:"optEnd",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_END}),this.$=a[s-1];break;case 29:a[s-1].unshift({type:"altStart",altText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.ALT_START}),a[s-1].push({type:"altEnd",signalType:r.LINETYPE.ALT_END}),this.$=a[s-1];break;case 30:a[s-1].unshift({type:"parStart",parText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.PAR_START}),a[s-1].push({type:"parEnd",signalType:r.LINETYPE.PAR_END}),this.$=a[s-1];break;case 33:this.$=a[s-3].concat([{type:"and",parText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.PAR_AND},a[s]]);break;case 35:this.$=a[s-3].concat([{type:"else",altText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.ALT_ELSE},a[s]]);break;case 36:this.$=[a[s-1],{type:"addNote",placement:a[s-2],actor:a[s-1].actor,text:a[s]}];break;case 37:a[s-2]=[].concat(a[s-1],a[s-1]).slice(0,2),a[s-2][0]=a[s-2][0].actor,a[s-2][1]=a[s-2][1].actor,this.$=[a[s-1],{type:"addNote",placement:r.PLACEMENT.OVER,actor:a[s-2].slice(0,2),text:a[s]}];break;case 38:this.$=[a[s-1],{type:"addLinks",actor:a[s-1].actor,text:a[s]}];break;case 39:this.$=[a[s-1],{type:"addALink",actor:a[s-1].actor,text:a[s]}];break;case 40:this.$=[a[s-1],{type:"addProperties",actor:a[s-1].actor,text:a[s]}];break;case 41:this.$=[a[s-1],{type:"addDetails",actor:a[s-1].actor,text:a[s]}];break;case 44:this.$=[a[s-2],a[s]];break;case 46:this.$=r.PLACEMENT.LEFTOF;break;case 47:this.$=r.PLACEMENT.RIGHTOF;break;case 48:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]}];break;case 49:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-4]}];break;case 50:this.$=[a[s-3],a[s-1],{type:"addMessage",from:a[s-3].actor,to:a[s-1].actor,signalType:a[s-2],msg:a[s]}];break;case 51:this.$={type:"addParticipant",actor:a[s]};break;case 52:this.$=r.LINETYPE.SOLID_OPEN;break;case 53:this.$=r.LINETYPE.DOTTED_OPEN;break;case 54:this.$=r.LINETYPE.SOLID;break;case 55:this.$=r.LINETYPE.DOTTED;break;case 56:this.$=r.LINETYPE.SOLID_CROSS;break;case 57:this.$=r.LINETYPE.DOTTED_CROSS;break;case 58:this.$=r.LINETYPE.SOLID_POINT;break;case 59:this.$=r.LINETYPE.DOTTED_POINT;break;case 60:this.$=r.parseMessage(a[s].trim().substring(1));break;case 61:r.parseDirective("%%{","open_directive");break;case 62:r.parseDirective(a[s],"type_directive");break;case 63:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 64:r.parseDirective("}%%","close_directive","sequence")}},table:[{3:1,4:e,5:n,6:4,7:r,11:6,67:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,11:6,67:i},{3:9,4:e,5:n,6:4,7:r,11:6,67:i},{3:10,4:e,5:n,6:4,7:r,11:6,67:i},t([1,4,5,16,20,22,23,24,30,32,34,35,36,38,42,46,47,48,49,57,67],a,{8:11}),{12:12,68:[1,13]},{68:[2,61]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{13:43,14:[1,44],70:E},t([14,70],[2,62]),t(C,[2,6]),{6:35,10:46,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},t(C,[2,8]),t(C,[2,9]),{17:47,57:T},{17:48,57:T},{5:[1,49]},t(C,[2,17]),{17:50,57:T},{17:51,57:T},{5:[1,52]},{5:[1,53]},{5:[1,54]},{5:[1,55]},{5:[1,56]},{31:57,66:S},{19:[1,59]},{19:[1,60]},{19:[1,61]},{19:[1,62]},{19:[1,63]},t(C,[2,31]),{54:64,58:[1,65],59:[1,66],60:[1,67],61:[1,68],62:[1,69],63:[1,70],64:[1,71],65:[1,72]},{43:73,44:[1,74],52:[1,75],53:[1,76]},{17:77,57:T},{17:78,57:T},{17:79,57:T},{17:80,57:T},t([5,18,51,58,59,60,61,62,63,64,65,66],[2,51]),{5:[1,81]},{15:82,69:[1,83]},{5:[2,64]},t(C,[2,7]),{5:[1,85],18:[1,84]},{5:[1,87],18:[1,86]},t(C,[2,16]),{5:[1,88]},{5:[1,89]},t(C,[2,20]),t(C,[2,21]),t(C,[2,22]),t(C,[2,23]),t(C,[2,24]),{5:[1,90]},{5:[2,60]},t(A,a,{8:91}),t(A,a,{8:92}),t(A,a,{8:93}),t(M,a,{37:94,8:95}),t(N,a,{39:96,8:97}),{17:100,55:[1,98],56:[1,99],57:T},t(D,[2,52]),t(D,[2,53]),t(D,[2,54]),t(D,[2,55]),t(D,[2,56]),t(D,[2,57]),t(D,[2,58]),t(D,[2,59]),{17:101,57:T},{17:103,45:102,57:T},{57:[2,46]},{57:[2,47]},{31:104,66:S},{31:105,66:S},{31:106,66:S},{31:107,66:S},t(O,[2,10]),{13:108,70:E},{70:[2,63]},{19:[1,109]},t(C,[2,13]),{19:[1,110]},t(C,[2,15]),t(C,[2,18]),t(C,[2,19]),t(C,[2,25]),{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,111],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,112],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,113],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{33:[1,114]},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[2,34],34:y,35:g,36:m,38:v,41:[1,115],42:b,46:_,47:x,48:w,49:k,57:T,67:i},{33:[1,116]},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[2,32],34:y,35:g,36:m,38:v,40:[1,117],42:b,46:_,47:x,48:w,49:k,57:T,67:i},{17:118,57:T},{17:119,57:T},{31:120,66:S},{31:121,66:S},{31:122,66:S},{51:[1,123],66:[2,45]},{5:[2,38]},{5:[2,39]},{5:[2,40]},{5:[2,41]},{5:[1,124]},{5:[1,125]},{5:[1,126]},t(C,[2,26]),t(C,[2,27]),t(C,[2,28]),t(C,[2,29]),{19:[1,127]},t(C,[2,30]),{19:[1,128]},{31:129,66:S},{31:130,66:S},{5:[2,50]},{5:[2,36]},{5:[2,37]},{17:131,57:T},t(O,[2,11]),t(C,[2,12]),t(C,[2,14]),t(M,a,{8:95,37:132}),t(N,a,{8:97,39:133}),{5:[2,48]},{5:[2,49]},{66:[2,44]},{33:[2,35]},{33:[2,33]}],defaultActions:{7:[2,61],8:[2,1],9:[2,2],10:[2,3],45:[2,64],58:[2,60],75:[2,46],76:[2,47],83:[2,63],104:[2,38],105:[2,39],106:[2,40],107:[2,41],120:[2,50],121:[2,36],122:[2,37],129:[2,48],130:[2,49],131:[2,44],132:[2,35],133:[2,33]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},L={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),67;case 1:return this.begin("type_directive"),68;case 2:return this.popState(),this.begin("arg_directive"),14;case 3:return this.popState(),this.popState(),70;case 4:return 69;case 5:case 39:case 52:return 5;case 6:case 7:case 8:case 9:case 10:break;case 11:return this.begin("ID"),16;case 12:return this.begin("ID"),20;case 13:return e.yytext=e.yytext.trim(),this.begin("ALIAS"),57;case 14:return this.popState(),this.popState(),this.begin("LINE"),18;case 15:return this.popState(),this.popState(),5;case 16:return this.begin("LINE"),32;case 17:return this.begin("LINE"),34;case 18:return this.begin("LINE"),35;case 19:return this.begin("LINE"),36;case 20:return this.begin("LINE"),41;case 21:return this.begin("LINE"),38;case 22:return this.begin("LINE"),40;case 23:return this.popState(),19;case 24:return 33;case 25:return 52;case 26:return 53;case 27:return 46;case 28:return 47;case 29:return 48;case 30:return 49;case 31:return 44;case 32:return 42;case 33:return this.begin("ID"),23;case 34:return this.begin("ID"),24;case 35:return 30;case 36:return 7;case 37:return 22;case 38:return 51;case 40:return e.yytext=e.yytext.trim(),57;case 41:return 60;case 42:return 61;case 43:return 58;case 44:return 59;case 45:return 62;case 46:return 63;case 47:return 64;case 48:return 65;case 49:return 66;case 50:return 55;case 51:return 56;case 53:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:participant\b)/i,/^(?:actor\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:links\b)/i,/^(?:link\b)/i,/^(?:properties\b)/i,/^(?:details\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+((?!(-x|--x|-\)|--\)))[\-]*[^\+\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?:-[\)])/i,/^(?:--[\)])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1,8],inclusive:!1},type_directive:{rules:[2,3,8],inclusive:!1},arg_directive:{rules:[3,4,8],inclusive:!1},ID:{rules:[7,8,13],inclusive:!1},ALIAS:{rules:[7,8,14,15],inclusive:!1},LINE:{rules:[7,8,23],inclusive:!1},INITIAL:{rules:[0,5,6,8,9,10,11,12,16,17,18,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53],inclusive:!0}}};function I(){this.yy={}}return B.lexer=L,I.prototype=B,B.Parser=I,new I}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1993).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3584:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,19],u=[1,20],l=[1,21],h=[1,22],f=[1,30],d=[1,23],p=[1,24],y=[1,25],g=[1,26],m=[1,27],v=[1,32],b=[1,33],_=[1,34],x=[1,35],w=[1,31],k=[1,38],T=[1,4,5,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],E=[1,4,5,12,13,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],C=[1,4,5,7,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],S=[4,5,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],A={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,directive:6,SD:7,document:8,line:9,statement:10,idStatement:11,DESCR:12,"--\x3e":13,HIDE_EMPTY:14,scale:15,WIDTH:16,COMPOSIT_STATE:17,STRUCT_START:18,STRUCT_STOP:19,STATE_DESCR:20,AS:21,ID:22,FORK:23,JOIN:24,CHOICE:25,CONCURRENT:26,note:27,notePosition:28,NOTE_TEXT:29,direction:30,openDirective:31,typeDirective:32,closeDirective:33,":":34,argDirective:35,direction_tb:36,direction_bt:37,direction_rl:38,direction_lr:39,eol:40,";":41,EDGE_STATE:42,left_of:43,right_of:44,open_directive:45,type_directive:46,arg_directive:47,close_directive:48,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",7:"SD",12:"DESCR",13:"--\x3e",14:"HIDE_EMPTY",15:"scale",16:"WIDTH",17:"COMPOSIT_STATE",18:"STRUCT_START",19:"STRUCT_STOP",20:"STATE_DESCR",21:"AS",22:"ID",23:"FORK",24:"JOIN",25:"CHOICE",26:"CONCURRENT",27:"note",29:"NOTE_TEXT",34:":",36:"direction_tb",37:"direction_bt",38:"direction_rl",39:"direction_lr",41:";",42:"EDGE_STATE",43:"left_of",44:"right_of",45:"open_directive",46:"type_directive",47:"arg_directive",48:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[10,1],[10,2],[10,3],[10,4],[10,1],[10,2],[10,1],[10,4],[10,3],[10,6],[10,1],[10,1],[10,1],[10,1],[10,4],[10,4],[10,1],[10,1],[6,3],[6,5],[30,1],[30,1],[30,1],[30,1],[40,1],[40,1],[11,1],[11,1],[28,1],[28,1],[31,1],[32,1],[35,1],[33,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.setRootDoc(a[s]),a[s];case 5:this.$=[];break;case 6:"nl"!=a[s]&&(a[s-1].push(a[s]),this.$=a[s-1]);break;case 7:case 8:case 36:case 37:this.$=a[s];break;case 9:this.$="nl";break;case 10:this.$={stmt:"state",id:a[s],type:"default",description:""};break;case 11:this.$={stmt:"state",id:a[s-1],type:"default",description:r.trimColon(a[s])};break;case 12:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-2],type:"default",description:""},state2:{stmt:"state",id:a[s],type:"default",description:""}};break;case 13:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-3],type:"default",description:""},state2:{stmt:"state",id:a[s-1],type:"default",description:""},description:a[s].substr(1).trim()};break;case 17:this.$={stmt:"state",id:a[s-3],type:"default",description:"",doc:a[s-1]};break;case 18:var c=a[s],u=a[s-2].trim();if(a[s].match(":")){var l=a[s].split(":");c=l[0],u=[u,l[1]]}this.$={stmt:"state",id:c,type:"default",description:u};break;case 19:this.$={stmt:"state",id:a[s-3],type:"default",description:a[s-5],doc:a[s-1]};break;case 20:this.$={stmt:"state",id:a[s],type:"fork"};break;case 21:this.$={stmt:"state",id:a[s],type:"join"};break;case 22:this.$={stmt:"state",id:a[s],type:"choice"};break;case 23:this.$={stmt:"state",id:r.getDividerId(),type:"divider"};break;case 24:this.$={stmt:"state",id:a[s-1].trim(),note:{position:a[s-2].trim(),text:a[s].trim()}};break;case 30:r.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 31:r.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 32:r.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 33:r.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 40:r.parseDirective("%%{","open_directive");break;case 41:r.parseDirective(a[s],"type_directive");break;case 42:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 43:r.parseDirective("}%%","close_directive","state")}},table:[{3:1,4:e,5:n,6:4,7:r,31:6,45:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,31:6,45:i},{3:9,4:e,5:n,6:4,7:r,31:6,45:i},{3:10,4:e,5:n,6:4,7:r,31:6,45:i},t([1,4,5,14,15,17,20,22,23,24,25,26,27,36,37,38,39,42,45],a,{8:11}),{32:12,46:[1,13]},{46:[2,40]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},{33:36,34:[1,37],48:k},t([34,48],[2,41]),t(T,[2,6]),{6:28,10:39,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,8]),t(T,[2,9]),t(T,[2,10],{12:[1,40],13:[1,41]}),t(T,[2,14]),{16:[1,42]},t(T,[2,16],{18:[1,43]}),{21:[1,44]},t(T,[2,20]),t(T,[2,21]),t(T,[2,22]),t(T,[2,23]),{28:45,29:[1,46],43:[1,47],44:[1,48]},t(T,[2,26]),t(T,[2,27]),t(E,[2,36]),t(E,[2,37]),t(T,[2,30]),t(T,[2,31]),t(T,[2,32]),t(T,[2,33]),t(C,[2,28]),{35:49,47:[1,50]},t(C,[2,43]),t(T,[2,7]),t(T,[2,11]),{11:51,22:f,42:w},t(T,[2,15]),t(S,a,{8:52}),{22:[1,53]},{22:[1,54]},{21:[1,55]},{22:[2,38]},{22:[2,39]},{33:56,48:k},{48:[2,42]},t(T,[2,12],{12:[1,57]}),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,58],20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,18],{18:[1,59]}),{29:[1,60]},{22:[1,61]},t(C,[2,29]),t(T,[2,13]),t(T,[2,17]),t(S,a,{8:62}),t(T,[2,24]),t(T,[2,25]),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,63],20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,19])],defaultActions:{7:[2,40],8:[2,1],9:[2,2],10:[2,3],47:[2,38],48:[2,39],50:[2,42]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},M={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:case 26:return 36;case 1:case 27:return 37;case 2:case 28:return 38;case 3:case 29:return 39;case 4:return this.begin("open_directive"),45;case 5:return this.begin("type_directive"),46;case 6:return this.popState(),this.begin("arg_directive"),34;case 7:return this.popState(),this.popState(),48;case 8:return 47;case 9:case 10:case 12:case 13:case 14:case 15:case 39:case 45:break;case 11:case 59:return 5;case 16:return this.pushState("SCALE"),15;case 17:return 16;case 18:case 33:case 36:this.popState();break;case 19:this.pushState("STATE");break;case 20:case 23:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),23;case 21:case 24:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),24;case 22:case 25:return this.popState(),e.yytext=e.yytext.slice(0,-10).trim(),25;case 30:this.begin("STATE_STRING");break;case 31:return this.popState(),this.pushState("STATE_ID"),"AS";case 32:case 47:return this.popState(),"ID";case 34:return"STATE_DESCR";case 35:return 17;case 37:return this.popState(),this.pushState("struct"),18;case 38:return this.popState(),19;case 40:return this.begin("NOTE"),27;case 41:return this.popState(),this.pushState("NOTE_ID"),43;case 42:return this.popState(),this.pushState("NOTE_ID"),44;case 43:this.popState(),this.pushState("FLOATING_NOTE");break;case 44:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 46:return"NOTE_TEXT";case 48:return this.popState(),this.pushState("NOTE_TEXT"),22;case 49:return this.popState(),e.yytext=e.yytext.substr(2).trim(),29;case 50:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),29;case 51:case 52:return 7;case 53:return 14;case 54:return 42;case 55:return 22;case 56:return e.yytext=e.yytext.trim(),12;case 57:return 13;case 58:return 26;case 60:return"INVALID"}},rules:[/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[13,14],inclusive:!1},close_directive:{rules:[13,14],inclusive:!1},arg_directive:{rules:[7,8,13,14],inclusive:!1},type_directive:{rules:[6,7,13,14],inclusive:!1},open_directive:{rules:[5,13,14],inclusive:!1},struct:{rules:[13,14,19,26,27,28,29,38,39,40,54,55,56,57,58],inclusive:!1},FLOATING_NOTE_ID:{rules:[47],inclusive:!1},FLOATING_NOTE:{rules:[44,45,46],inclusive:!1},NOTE_TEXT:{rules:[49,50],inclusive:!1},NOTE_ID:{rules:[48],inclusive:!1},NOTE:{rules:[41,42,43],inclusive:!1},SCALE:{rules:[17,18],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[32],inclusive:!1},STATE_STRING:{rules:[33,34],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[13,14,20,21,22,23,24,25,30,31,35,36,37],inclusive:!1},ID:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,12,14,15,16,19,37,40,51,52,53,54,55,56,57,59,60],inclusive:!0}}};function N(){this.yy={}}return A.lexer=M,N.prototype=A,A.Parser=N,new N}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(3069).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9763:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,17,18,19,21],i=[1,15],a=[1,16],o=[1,17],s=[1,21],c=[4,6,9,11,17,18,19,21],u={trace:function(){},yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,title:17,section:18,taskName:19,taskData:20,open_directive:21,type_directive:22,arg_directive:23,close_directive:24,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",17:"title",18:"section",19:"taskName",20:"taskData",21:"open_directive",22:"type_directive",23:"arg_directive",24:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,1],[10,2],[10,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 11:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 12:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 13:r.addTask(a[s-1],a[s]),this.$="task";break;case 15:r.parseDirective("%%{","open_directive");break;case 16:r.parseDirective(a[s],"type_directive");break;case 17:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 18:r.parseDirective("}%%","close_directive","journey")}},table:[{3:1,4:e,7:3,12:4,21:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,21:n},{13:8,22:[1,9]},{22:[2,15]},{6:[1,10],7:18,8:11,9:[1,12],10:13,11:[1,14],12:4,17:i,18:a,19:o,21:n},{1:[2,2]},{14:19,15:[1,20],24:s},t([15,24],[2,16]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:18,10:22,12:4,17:i,18:a,19:o,21:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,12]),{20:[1,23]},t(r,[2,14]),{11:[1,24]},{16:25,23:[1,26]},{11:[2,18]},t(r,[2,5]),t(r,[2,13]),t(c,[2,9]),{14:27,24:s},{24:[2,17]},{11:[1,28]},t(c,[2,10])],defaultActions:{5:[2,15],7:[2,2],21:[2,18],26:[2,17]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},l={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),21;case 1:return this.begin("type_directive"),22;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),24;case 4:return 23;case 5:case 6:case 8:case 9:break;case 7:return 11;case 10:return 4;case 11:return 17;case 12:return 18;case 13:return 19;case 14:return 20;case 15:return 15;case 16:return 6;case 17:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,13,14,15,16,17],inclusive:!0}}};function h(){this.yy={}}return u.lexer=l,h.prototype=u,u.Parser=h,new h}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(9143).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9609:t=>{"use strict";var e=/^(%20|\s)*(javascript|data)/im,n=/[^\x20-\x7E]/gim,r=/^([^:]+):/gm,i=[".","/"];t.exports={sanitizeUrl:function(t){if(!t)return"about:blank";var a,o,s=t.replace(n,"").trim();return function(t){return i.indexOf(t[0])>-1}(s)?s:(o=s.match(r))?(a=o[0],e.test(a)?"about:blank":s):"about:blank"}}},3841:t=>{t.exports=function(t,e){return t.intersect(e)}},7458:(t,e,n)=>{"use strict";n.d(e,{default:()=>sE});var r=n(1941),i=n.n(r),a={debug:1,info:2,warn:3,error:4,fatal:5},o={debug:function(){},info:function(){},warn:function(){},error:function(){},fatal:function(){}},s=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"fatal";isNaN(t)&&(t=t.toLowerCase(),void 0!==a[t]&&(t=a[t])),o.trace=function(){},o.debug=function(){},o.info=function(){},o.warn=function(){},o.error=function(){},o.fatal=function(){},t<=a.fatal&&(o.fatal=console.error?console.error.bind(console,c("FATAL"),"color: orange"):console.log.bind(console,"",c("FATAL"))),t<=a.error&&(o.error=console.error?console.error.bind(console,c("ERROR"),"color: orange"):console.log.bind(console,"",c("ERROR"))),t<=a.warn&&(o.warn=console.warn?console.warn.bind(console,c("WARN"),"color: orange"):console.log.bind(console,"",c("WARN"))),t<=a.info&&(o.info=console.info?console.info.bind(console,c("INFO"),"color: lightblue"):console.log.bind(console,"",c("INFO"))),t<=a.debug&&(o.debug=console.debug?console.debug.bind(console,c("DEBUG"),"color: lightgreen"):console.log.bind(console,"",c("DEBUG")))},c=function(t){var e=i()().format("ss.SSS");return"%c".concat(e," : ").concat(t," : ")};function u(t,e){let n;if(void 0===e)for(const e of t)null!=e&&(n=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n=i)&&(n=i)}return n}function l(t,e){let n;if(void 0===e)for(const e of t)null!=e&&(n>e||void 0===n&&e>=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n>i||void 0===n&&i>=i)&&(n=i)}return n}function h(t){return t}var f=1e-6;function d(t){return"translate("+t+",0)"}function p(t){return"translate(0,"+t+")"}function y(t){return e=>+t(e)}function g(t,e){return e=Math.max(0,t.bandwidth()-2*e)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function m(){return!this.__axis}function v(t,e){var n=[],r=null,i=null,a=6,o=6,s=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,u=1===t||4===t?-1:1,l=4===t||2===t?"x":"y",v=1===t||3===t?d:p;function b(d){var p=null==r?e.ticks?e.ticks.apply(e,n):e.domain():r,b=null==i?e.tickFormat?e.tickFormat.apply(e,n):h:i,_=Math.max(a,0)+s,x=e.range(),w=+x[0]+c,k=+x[x.length-1]+c,T=(e.bandwidth?g:y)(e.copy(),c),E=d.selection?d.selection():d,C=E.selectAll(".domain").data([null]),S=E.selectAll(".tick").data(p,e).order(),A=S.exit(),M=S.enter().append("g").attr("class","tick"),N=S.select("line"),D=S.select("text");C=C.merge(C.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),S=S.merge(M),N=N.merge(M.append("line").attr("stroke","currentColor").attr(l+"2",u*a)),D=D.merge(M.append("text").attr("fill","currentColor").attr(l,u*_).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),d!==E&&(C=C.transition(d),S=S.transition(d),N=N.transition(d),D=D.transition(d),A=A.transition(d).attr("opacity",f).attr("transform",(function(t){return isFinite(t=T(t))?v(t+c):this.getAttribute("transform")})),M.attr("opacity",f).attr("transform",(function(t){var e=this.parentNode.__axis;return v((e&&isFinite(e=e(t))?e:T(t))+c)}))),A.remove(),C.attr("d",4===t||2===t?o?"M"+u*o+","+w+"H"+c+"V"+k+"H"+u*o:"M"+c+","+w+"V"+k:o?"M"+w+","+u*o+"V"+c+"H"+k+"V"+u*o:"M"+w+","+c+"H"+k),S.attr("opacity",1).attr("transform",(function(t){return v(T(t)+c)})),N.attr(l+"2",u*a),D.attr(l,u*_).text(b),E.filter(m).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),E.each((function(){this.__axis=T}))}return b.scale=function(t){return arguments.length?(e=t,b):e},b.ticks=function(){return n=Array.from(arguments),b},b.tickArguments=function(t){return arguments.length?(n=null==t?[]:Array.from(t),b):n.slice()},b.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),b):r&&r.slice()},b.tickFormat=function(t){return arguments.length?(i=t,b):i},b.tickSize=function(t){return arguments.length?(a=o=+t,b):a},b.tickSizeInner=function(t){return arguments.length?(a=+t,b):a},b.tickSizeOuter=function(t){return arguments.length?(o=+t,b):o},b.tickPadding=function(t){return arguments.length?(s=+t,b):s},b.offset=function(t){return arguments.length?(c=+t,b):c},b}function b(){}function _(t){return null==t?b:function(){return this.querySelector(t)}}function x(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function w(){return[]}function k(t){return null==t?w:function(){return this.querySelectorAll(t)}}function T(t){return function(){return this.matches(t)}}function E(t){return function(e){return e.matches(t)}}var C=Array.prototype.find;function S(){return this.firstElementChild}var A=Array.prototype.filter;function M(){return Array.from(this.children)}function N(t){return new Array(t.length)}function D(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function O(t){return function(){return t}}function B(t,e,n,r,i,a){for(var o,s=0,c=e.length,u=a.length;se?1:t>=e?0:NaN}D.prototype={constructor:D,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var P="http://www.w3.org/1999/xhtml";const j={svg:"http://www.w3.org/2000/svg",xhtml:P,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Y(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),j.hasOwnProperty(e)?{space:j[e],local:t}:t}function z(t){return function(){this.removeAttribute(t)}}function U(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,e){return function(){this.setAttribute(t,e)}}function H(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function $(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function W(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function V(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function G(t){return function(){this.style.removeProperty(t)}}function X(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Z(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Q(t,e){return t.style.getPropertyValue(e)||V(t).getComputedStyle(t,null).getPropertyValue(e)}function K(t){return function(){delete this[t]}}function J(t,e){return function(){this[t]=e}}function tt(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function et(t){return t.trim().split(/^|\s+/)}function nt(t){return t.classList||new rt(t)}function rt(t){this._node=t,this._names=et(t.getAttribute("class")||"")}function it(t,e){for(var n=nt(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function Et(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Nt=[null];function Dt(t,e){this._groups=t,this._parents=e}function Ot(){return new Dt([[document.documentElement]],Nt)}Dt.prototype=Ot.prototype={constructor:Dt,select:function(t){"function"!=typeof t&&(t=_(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=F);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?G:"function"==typeof e?Z:X)(t,e,null==n?"":n)):Q(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?K:"function"==typeof e?tt:J)(t,e)):this.node()[t]},classed:function(t,e){var n=et(t+"");if(arguments.length<2){for(var r=nt(this.node()),i=-1,a=n.length;++i{}};function It(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function Pt(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--qt}()}finally{qt=0,function(){for(var t,e,n=zt,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:zt=e);Ut=t,re(r)}(),Vt=0}}function ne(){var t=Xt.now(),e=t-Wt;e>1e3&&(Gt-=e,Wt=t)}function re(t){qt||(Ht&&(Ht=clearTimeout(Ht)),t-Vt>24?(t<1/0&&(Ht=setTimeout(ee,t-Xt.now()-Gt)),$t&&($t=clearInterval($t))):($t||(Wt=Xt.now(),$t=setInterval(ne,1e3)),qt=1,Zt(ee)))}function ie(t,e,n){var r=new Jt;return e=null==e?0:+e,r.restart(n=>{r.stop(),t(n+e)},e,n),r}Jt.prototype=te.prototype={constructor:Jt,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Qt():+n)+(null==e?0:+e),this._next||Ut===this||(Ut?Ut._next=this:zt=this,Ut=this),this._call=t,this._time=n,re()},stop:function(){this._call&&(this._call=null,this._time=1/0,re())}};var ae=Yt("start","end","cancel","interrupt"),oe=[];function se(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return ie(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function ue(t,e){var n=le(t,e);if(n.state>3)throw new Error("too late; already running");return n}function le(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function he(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var fe,de=180/Math.PI,pe={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function ye(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:he(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:he(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:he(t,n)},{i:s-2,x:he(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?ze(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?ze(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Ne.exec(t))?new He(e[1],e[2],e[3],1):(e=De.exec(t))?new He(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Oe.exec(t))?ze(e[1],e[2],e[3],e[4]):(e=Be.exec(t))?ze(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Le.exec(t))?Ge(e[1],e[2]/100,e[3]/100,1):(e=Ie.exec(t))?Ge(e[1],e[2]/100,e[3]/100,e[4]):Re.hasOwnProperty(t)?Ye(Re[t]):"transparent"===t?new He(NaN,NaN,NaN,0):null}function Ye(t){return new He(t>>16&255,t>>8&255,255&t,1)}function ze(t,e,n,r){return r<=0&&(t=e=n=NaN),new He(t,e,n,r)}function Ue(t){return t instanceof Te||(t=je(t)),t?new He((t=t.rgb()).r,t.g,t.b,t.opacity):new He}function qe(t,e,n,r){return 1===arguments.length?Ue(t):new He(t,e,n,null==r?1:r)}function He(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function $e(){return"#"+Ve(this.r)+Ve(this.g)+Ve(this.b)}function We(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function Ve(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Ge(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Ze(t,e,n,r)}function Xe(t){if(t instanceof Ze)return new Ze(t.h,t.s,t.l,t.opacity);if(t instanceof Te||(t=je(t)),!t)return new Ze;if(t instanceof Ze)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new Ze(o,s,c,t.opacity)}function Ze(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function Qe(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function Ke(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}we(Te,je,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:Fe,formatHex:Fe,formatHsl:function(){return Xe(this).formatHsl()},formatRgb:Pe,toString:Pe}),we(He,qe,ke(Te,{brighter:function(t){return t=null==t?Ee:Math.pow(Ee,t),new He(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new He(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:$e,formatHex:$e,formatRgb:We,toString:We})),we(Ze,(function(t,e,n,r){return 1===arguments.length?Xe(t):new Ze(t,e,n,null==r?1:r)}),ke(Te,{brighter:function(t){return t=null==t?Ee:Math.pow(Ee,t),new Ze(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Ze(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new He(Qe(t>=240?t-240:t+120,i,r),Qe(t,i,r),Qe(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const Je=t=>()=>t;function tn(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):Je(isNaN(t)?e:t)}const en=function t(e){var n=function(t){return 1==(t=+t)?tn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):Je(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=qe(t)).r,(e=qe(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=tn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function nn(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:he(n,r)})),a=an.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?ce:ue;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var Tn=Bt.prototype.constructor;function En(t){return function(){this.style.removeProperty(t)}}function Cn(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function Sn(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Cn(t,a,n)),r}return a._value=e,a}function An(t){return function(e){this.textContent=t.call(this,e)}}function Mn(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&An(r)),e}return r._value=t,r}var Nn=0;function Dn(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function On(){return++Nn}var Bn=Bt.prototype;Dn.prototype=function(t){return Bt().transition(t)}.prototype={constructor:Dn,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=_(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Bt.prototype.transition=function(t){var e,n;t instanceof Dn?(e=t._id,t=t._name):(e=On(),(n=Ln).time=Qt(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;a>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?ar(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?ar(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Gn.exec(t))?new cr(e[1],e[2],e[3],1):(e=Xn.exec(t))?new cr(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Zn.exec(t))?ar(e[1],e[2],e[3],e[4]):(e=Qn.exec(t))?ar(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Kn.exec(t))?fr(e[1],e[2]/100,e[3]/100,1):(e=Jn.exec(t))?fr(e[1],e[2]/100,e[3]/100,e[4]):tr.hasOwnProperty(t)?ir(tr[t]):"transparent"===t?new cr(NaN,NaN,NaN,0):null}function ir(t){return new cr(t>>16&255,t>>8&255,255&t,1)}function ar(t,e,n,r){return r<=0&&(t=e=n=NaN),new cr(t,e,n,r)}function or(t){return t instanceof Un||(t=rr(t)),t?new cr((t=t.rgb()).r,t.g,t.b,t.opacity):new cr}function sr(t,e,n,r){return 1===arguments.length?or(t):new cr(t,e,n,null==r?1:r)}function cr(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function ur(){return"#"+hr(this.r)+hr(this.g)+hr(this.b)}function lr(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function hr(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function fr(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new pr(t,e,n,r)}function dr(t){if(t instanceof pr)return new pr(t.h,t.s,t.l,t.opacity);if(t instanceof Un||(t=rr(t)),!t)return new pr;if(t instanceof pr)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new pr(o,s,c,t.opacity)}function pr(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function yr(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}Yn(Un,rr,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:er,formatHex:er,formatHsl:function(){return dr(this).formatHsl()},formatRgb:nr,toString:nr}),Yn(cr,sr,zn(Un,{brighter:function(t){return t=null==t?qn:Math.pow(qn,t),new cr(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new cr(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:ur,formatHex:ur,formatRgb:lr,toString:lr})),Yn(pr,(function(t,e,n,r){return 1===arguments.length?dr(t):new pr(t,e,n,null==r?1:r)}),zn(Un,{brighter:function(t){return t=null==t?qn:Math.pow(qn,t),new pr(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new pr(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new cr(yr(t>=240?t-240:t+120,i,r),yr(t,i,r),yr(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const gr=Math.PI/180,mr=180/Math.PI,vr=6/29*3*(6/29);function br(t){if(t instanceof _r)return new _r(t.l,t.a,t.b,t.opacity);if(t instanceof Sr)return Ar(t);t instanceof cr||(t=or(t));var e,n,r=Tr(t.r),i=Tr(t.g),a=Tr(t.b),o=xr((.2225045*r+.7168786*i+.0606169*a)/1);return r===i&&i===a?e=n=o:(e=xr((.4360747*r+.3850649*i+.1430804*a)/.96422),n=xr((.0139322*r+.0971045*i+.7141733*a)/.82521)),new _r(116*o-16,500*(e-o),200*(o-n),t.opacity)}function _r(t,e,n,r){this.l=+t,this.a=+e,this.b=+n,this.opacity=+r}function xr(t){return t>.008856451679035631?Math.pow(t,1/3):t/vr+4/29}function wr(t){return t>6/29?t*t*t:vr*(t-4/29)}function kr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Tr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Er(t){if(t instanceof Sr)return new Sr(t.h,t.c,t.l,t.opacity);if(t instanceof _r||(t=br(t)),0===t.a&&0===t.b)return new Sr(NaN,0()=>t;function Nr(t,e){return function(n){return t+n*e}}function Dr(t,e){var n=e-t;return n?Nr(t,n):Mr(isNaN(t)?e:t)}function Or(t){return function(e,n){var r=t((e=Cr(e)).h,(n=Cr(n)).h),i=Dr(e.c,n.c),a=Dr(e.l,n.l),o=Dr(e.opacity,n.opacity);return function(t){return e.h=r(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const Br=Or((function(t,e){var n=e-t;return n?Nr(t,n>180||n<-180?n-360*Math.round(n/360):n):Mr(isNaN(t)?e:t)}));Or(Dr);var Lr=Math.sqrt(50),Ir=Math.sqrt(10),Rr=Math.sqrt(2);function Fr(t,e,n){var r=(e-t)/Math.max(0,n),i=Math.floor(Math.log(r)/Math.LN10),a=r/Math.pow(10,i);return i>=0?(a>=Lr?10:a>=Ir?5:a>=Rr?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(a>=Lr?10:a>=Ir?5:a>=Rr?2:1)}function Pr(t,e,n){var r=Math.abs(e-t)/Math.max(0,n),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),a=r/i;return a>=Lr?i*=10:a>=Ir?i*=5:a>=Rr&&(i*=2),ee?1:t>=e?0:NaN}function Yr(t){let e=t,n=t,r=t;function i(t,e,i=0,a=t.length){if(i>>1;r(t[n],e)<0?i=n+1:a=n}while(it(e)-n,n=jr,r=(e,n)=>jr(t(e),n)),{left:i,center:function(t,n,r=0,a=t.length){const o=i(t,n,r,a-1);return o>r&&e(t[o-1],n)>-e(t[o],n)?o-1:o},right:function(t,e,i=0,a=t.length){if(i>>1;r(t[n],e)<=0?i=n+1:a=n}while(i>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?ui(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?ui(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Kr.exec(t))?new fi(e[1],e[2],e[3],1):(e=Jr.exec(t))?new fi(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=ti.exec(t))?ui(e[1],e[2],e[3],e[4]):(e=ei.exec(t))?ui(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=ni.exec(t))?gi(e[1],e[2]/100,e[3]/100,1):(e=ri.exec(t))?gi(e[1],e[2]/100,e[3]/100,e[4]):ii.hasOwnProperty(t)?ci(ii[t]):"transparent"===t?new fi(NaN,NaN,NaN,0):null}function ci(t){return new fi(t>>16&255,t>>8&255,255&t,1)}function ui(t,e,n,r){return r<=0&&(t=e=n=NaN),new fi(t,e,n,r)}function li(t){return t instanceof Wr||(t=si(t)),t?new fi((t=t.rgb()).r,t.g,t.b,t.opacity):new fi}function hi(t,e,n,r){return 1===arguments.length?li(t):new fi(t,e,n,null==r?1:r)}function fi(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function di(){return"#"+yi(this.r)+yi(this.g)+yi(this.b)}function pi(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function yi(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function gi(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new vi(t,e,n,r)}function mi(t){if(t instanceof vi)return new vi(t.h,t.s,t.l,t.opacity);if(t instanceof Wr||(t=si(t)),!t)return new vi;if(t instanceof vi)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new vi(o,s,c,t.opacity)}function vi(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function bi(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function _i(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}Hr(Wr,si,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:ai,formatHex:ai,formatHsl:function(){return mi(this).formatHsl()},formatRgb:oi,toString:oi}),Hr(fi,hi,$r(Wr,{brighter:function(t){return t=null==t?Vr:Math.pow(Vr,t),new fi(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new fi(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:di,formatHex:di,formatRgb:pi,toString:pi})),Hr(vi,(function(t,e,n,r){return 1===arguments.length?mi(t):new vi(t,e,n,null==r?1:r)}),$r(Wr,{brighter:function(t){return t=null==t?Vr:Math.pow(Vr,t),new vi(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new vi(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new fi(bi(t>=240?t-240:t+120,i,r),bi(t,i,r),bi(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const xi=t=>()=>t;function wi(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):xi(isNaN(t)?e:t)}const ki=function t(e){var n=function(t){return 1==(t=+t)?wi:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):xi(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=hi(t)).r,(e=hi(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=wi(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function Ti(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:Si(n,r)})),a=Ni.lastIndex;return ae&&(n=t,t=e,e=n),u=function(n){return Math.max(t,Math.min(e,n))}),r=c>2?Yi:ji,i=a=null,h}function h(e){return null==e||isNaN(e=+e)?n:(i||(i=r(o.map(t),s,c)))(t(u(e)))}return h.invert=function(n){return u(e((a||(a=r(s,o.map(t),Si)))(n)))},h.domain=function(t){return arguments.length?(o=Array.from(t,Ii),l()):o.slice()},h.range=function(t){return arguments.length?(s=Array.from(t),l()):s.slice()},h.rangeRound=function(t){return s=Array.from(t),c=Li,l()},h.clamp=function(t){return arguments.length?(u=!!t||Fi,l()):u!==Fi},h.interpolate=function(t){return arguments.length?(c=t,l()):c},h.unknown=function(t){return arguments.length?(n=t,h):n},function(n,r){return t=n,e=r,l()}}()(Fi,Fi)}function qi(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t)}return this}var Hi,$i=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Wi(t){if(!(e=$i.exec(t)))throw new Error("invalid format: "+t);var e;return new Vi({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function Vi(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Gi(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,r=t.slice(0,n);return[r.length>1?r[0]+r.slice(2):r,+t.slice(n+1)]}function Xi(t){return(t=Gi(Math.abs(t)))?t[1]:NaN}function Zi(t,e){var n=Gi(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Wi.prototype=Vi.prototype,Vi.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const Qi={"%":(t,e)=>(100*t).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>Zi(100*t,e),r:Zi,s:function(t,e){var n=Gi(t,e);if(!n)return t+"";var r=n[0],i=n[1],a=i-(Hi=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=r.length;return a===o?r:a>o?r+new Array(a-o+1).join("0"):a>0?r.slice(0,a)+"."+r.slice(a):"0."+new Array(1-a).join("0")+Gi(t,Math.max(0,e+a-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Ki(t){return t}var Ji,ta,ea,na=Array.prototype.map,ra=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function ia(t){var e=t.domain;return t.ticks=function(t){var n=e();return function(t,e,n){var r,i,a,o,s=-1;if(n=+n,(t=+t)==(e=+e)&&n>0)return[t];if((r=e0){let n=Math.round(t/o),r=Math.round(e/o);for(n*oe&&--r,a=new Array(i=r-n+1);++se&&--r,a=new Array(i=r-n+1);++s0;){if((i=Fr(c,u,n))===r)return a[o]=c,a[s]=u,e(a);if(i>0)c=Math.floor(c/i)*i,u=Math.ceil(u/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,u=Math.floor(u*i)/i}r=i}return t},t}Ji=function(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?Ki:(e=na.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,a=[],o=0,s=e[0],c=0;i>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),a.push(t.substring(i-=s,i+s)),!((c+=s+1)>r));)s=e[o=(o+1)%e.length];return a.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?Ki:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(na.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",u=void 0===t.minus?"−":t.minus+"",l=void 0===t.nan?"NaN":t.nan+"";function h(t){var e=(t=Wi(t)).fill,n=t.align,h=t.sign,f=t.symbol,d=t.zero,p=t.width,y=t.comma,g=t.precision,m=t.trim,v=t.type;"n"===v?(y=!0,v="g"):Qi[v]||(void 0===g&&(g=12),m=!0,v="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var b="$"===f?i:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",_="$"===f?a:/[%p]/.test(v)?c:"",x=Qi[v],w=/[defgprs%]/.test(v);function k(t){var i,a,c,f=b,k=_;if("c"===v)k=x(t)+k,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?l:x(Math.abs(t),g),m&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),T&&0==+t&&"+"!==h&&(T=!1),f=(T?"("===h?h:u:"-"===h||"("===h?"":h)+f,k=("s"===v?ra[8+Hi/3]:"")+k+(T&&"("===h?")":""),w)for(i=-1,a=t.length;++i(c=t.charCodeAt(i))||c>57){k=(46===c?o+t.slice(i+1):t.slice(i))+k,t=t.slice(0,i);break}}y&&!d&&(t=r(t,1/0));var E=f.length+t.length+k.length,C=E>1)+f+t+k+C.slice(E);break;default:t=C+f+t+k}return s(t)}return g=void 0===g?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),k.toString=function(){return t+""},k}return{format:h,formatPrefix:function(t,e){var n=h(((t=Wi(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Xi(e)/3))),i=Math.pow(10,-r),a=ra[8+r/3];return function(t){return n(i*t)+a}}}}({thousands:",",grouping:[3],currency:["$",""]}),ta=Ji.format,ea=Ji.formatPrefix;class aa extends Map{constructor(t,e=sa){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:e}}),null!=t)for(const[e,n]of t)this.set(e,n)}get(t){return super.get(oa(this,t))}has(t){return super.has(oa(this,t))}set(t,e){return super.set(function({_intern:t,_key:e},n){const r=e(n);return t.has(r)?t.get(r):(t.set(r,n),n)}(this,t),e)}delete(t){return super.delete(function({_intern:t,_key:e},n){const r=e(n);return t.has(r)&&(n=t.get(r),t.delete(r)),n}(this,t))}}function oa({_intern:t,_key:e},n){const r=e(n);return t.has(r)?t.get(r):n}function sa(t){return null!==t&&"object"==typeof t?t.valueOf():t}Set;const ca=Symbol("implicit"),ua=1e3,la=6e4,ha=36e5,fa=864e5,da=6048e5,pa=31536e6;var ya=new Date,ga=new Date;function ma(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return ya.setTime(+e),ga.setTime(+r),t(ya),t(ga),Math.floor(n(ya,ga))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}var va=ma((function(){}),(function(t,e){t.setTime(+t+e)}),(function(t,e){return e-t}));va.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?ma((function(e){e.setTime(Math.floor(e/t)*t)}),(function(e,n){e.setTime(+e+n*t)}),(function(e,n){return(n-e)/t})):va:null};const ba=va;va.range;var _a=ma((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,e){t.setTime(+t+e*ua)}),(function(t,e){return(e-t)/ua}),(function(t){return t.getUTCSeconds()}));const xa=_a;_a.range;var wa=ma((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*ua)}),(function(t,e){t.setTime(+t+e*la)}),(function(t,e){return(e-t)/la}),(function(t){return t.getMinutes()}));const ka=wa;wa.range;var Ta=ma((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*ua-t.getMinutes()*la)}),(function(t,e){t.setTime(+t+e*ha)}),(function(t,e){return(e-t)/ha}),(function(t){return t.getHours()}));const Ea=Ta;Ta.range;var Ca=ma(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*la)/fa,t=>t.getDate()-1);const Sa=Ca;function Aa(t){return ma((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*la)/da}))}Ca.range;var Ma=Aa(0),Na=Aa(1),Da=Aa(2),Oa=Aa(3),Ba=Aa(4),La=Aa(5),Ia=Aa(6),Ra=(Ma.range,Na.range,Da.range,Oa.range,Ba.range,La.range,Ia.range,ma((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,e){t.setMonth(t.getMonth()+e)}),(function(t,e){return e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()})));const Fa=Ra;Ra.range;var Pa=ma((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));Pa.every=function(t){return isFinite(t=Math.floor(t))&&t>0?ma((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const ja=Pa;Pa.range;var Ya=ma((function(t){t.setUTCSeconds(0,0)}),(function(t,e){t.setTime(+t+e*la)}),(function(t,e){return(e-t)/la}),(function(t){return t.getUTCMinutes()}));const za=Ya;Ya.range;var Ua=ma((function(t){t.setUTCMinutes(0,0,0)}),(function(t,e){t.setTime(+t+e*ha)}),(function(t,e){return(e-t)/ha}),(function(t){return t.getUTCHours()}));const qa=Ua;Ua.range;var Ha=ma((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/fa}),(function(t){return t.getUTCDate()-1}));const $a=Ha;function Wa(t){return ma((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/da}))}Ha.range;var Va=Wa(0),Ga=Wa(1),Xa=Wa(2),Za=Wa(3),Qa=Wa(4),Ka=Wa(5),Ja=Wa(6),to=(Va.range,Ga.range,Xa.range,Za.range,Qa.range,Ka.range,Ja.range,ma((function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCMonth(t.getUTCMonth()+e)}),(function(t,e){return e.getUTCMonth()-t.getUTCMonth()+12*(e.getUTCFullYear()-t.getUTCFullYear())}),(function(t){return t.getUTCMonth()})));const eo=to;to.range;var no=ma((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));no.every=function(t){return isFinite(t=Math.floor(t))&&t>0?ma((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const ro=no;function io(t,e,n,r,i,a){const o=[[xa,1,ua],[xa,5,5e3],[xa,15,15e3],[xa,30,3e4],[a,1,la],[a,5,3e5],[a,15,9e5],[a,30,18e5],[i,1,ha],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,fa],[r,2,1728e5],[n,1,da],[e,1,2592e6],[e,3,7776e6],[t,1,pa]];function s(e,n,r){const i=Math.abs(n-e)/r,a=Yr(([,,t])=>t).right(o,i);if(a===o.length)return t.every(Pr(e/pa,n/pa,r));if(0===a)return ba.every(Math.max(Pr(e,n,r),1));const[s,c]=o[i/o[a-1][2][t.toLowerCase(),e]))}function ko(t,e,n){var r=go.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function To(t,e,n){var r=go.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Eo(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Co(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function So(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function Ao(t,e,n){var r=go.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function Mo(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function No(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Do(t,e,n){var r=go.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function Oo(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Bo(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Lo(t,e,n){var r=go.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Io(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function Ro(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Fo(t,e,n){var r=go.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Po(t,e,n){var r=go.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function jo(t,e,n){var r=go.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function Yo(t,e,n){var r=mo.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function zo(t,e,n){var r=go.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Uo(t,e,n){var r=go.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function qo(t,e){return bo(t.getDate(),e,2)}function Ho(t,e){return bo(t.getHours(),e,2)}function $o(t,e){return bo(t.getHours()%12||12,e,2)}function Wo(t,e){return bo(1+Sa.count(ja(t),t),e,3)}function Vo(t,e){return bo(t.getMilliseconds(),e,3)}function Go(t,e){return Vo(t,e)+"000"}function Xo(t,e){return bo(t.getMonth()+1,e,2)}function Zo(t,e){return bo(t.getMinutes(),e,2)}function Qo(t,e){return bo(t.getSeconds(),e,2)}function Ko(t){var e=t.getDay();return 0===e?7:e}function Jo(t,e){return bo(Ma.count(ja(t)-1,t),e,2)}function ts(t){var e=t.getDay();return e>=4||0===e?Ba(t):Ba.ceil(t)}function es(t,e){return t=ts(t),bo(Ba.count(ja(t),t)+(4===ja(t).getDay()),e,2)}function ns(t){return t.getDay()}function rs(t,e){return bo(Na.count(ja(t)-1,t),e,2)}function is(t,e){return bo(t.getFullYear()%100,e,2)}function as(t,e){return bo((t=ts(t)).getFullYear()%100,e,2)}function os(t,e){return bo(t.getFullYear()%1e4,e,4)}function ss(t,e){var n=t.getDay();return bo((t=n>=4||0===n?Ba(t):Ba.ceil(t)).getFullYear()%1e4,e,4)}function cs(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+bo(e/60|0,"0",2)+bo(e%60,"0",2)}function us(t,e){return bo(t.getUTCDate(),e,2)}function ls(t,e){return bo(t.getUTCHours(),e,2)}function hs(t,e){return bo(t.getUTCHours()%12||12,e,2)}function fs(t,e){return bo(1+$a.count(ro(t),t),e,3)}function ds(t,e){return bo(t.getUTCMilliseconds(),e,3)}function ps(t,e){return ds(t,e)+"000"}function ys(t,e){return bo(t.getUTCMonth()+1,e,2)}function gs(t,e){return bo(t.getUTCMinutes(),e,2)}function ms(t,e){return bo(t.getUTCSeconds(),e,2)}function vs(t){var e=t.getUTCDay();return 0===e?7:e}function bs(t,e){return bo(Va.count(ro(t)-1,t),e,2)}function _s(t){var e=t.getUTCDay();return e>=4||0===e?Qa(t):Qa.ceil(t)}function xs(t,e){return t=_s(t),bo(Qa.count(ro(t),t)+(4===ro(t).getUTCDay()),e,2)}function ws(t){return t.getUTCDay()}function ks(t,e){return bo(Ga.count(ro(t)-1,t),e,2)}function Ts(t,e){return bo(t.getUTCFullYear()%100,e,2)}function Es(t,e){return bo((t=_s(t)).getUTCFullYear()%100,e,2)}function Cs(t,e){return bo(t.getUTCFullYear()%1e4,e,4)}function Ss(t,e){var n=t.getUTCDay();return bo((t=n>=4||0===n?Qa(t):Qa.ceil(t)).getUTCFullYear()%1e4,e,4)}function As(){return"+0000"}function Ms(){return"%"}function Ns(t){return+t}function Ds(t){return Math.floor(+t/1e3)}function Os(t){return new Date(t)}function Bs(t){return t instanceof Date?+t:+new Date(+t)}function Ls(t,e,n,r,i,a,o,s,c,u){var l=Ui(),h=l.invert,f=l.domain,d=u(".%L"),p=u(":%S"),y=u("%I:%M"),g=u("%I %p"),m=u("%a %d"),v=u("%b %d"),b=u("%B"),_=u("%Y");function x(t){return(c(t)=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Ns,s:Ds,S:Qo,u:Ko,U:Jo,V:es,w:ns,W:rs,x:null,X:null,y:is,Y:os,Z:cs,"%":Ms},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:us,e:us,f:ps,g:Es,G:Ss,H:ls,I:hs,j:fs,L:ds,m:ys,M:gs,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Ns,s:Ds,S:ms,u:vs,U:bs,V:xs,w:ws,W:ks,x:null,X:null,y:Ts,Y:Cs,Z:As,"%":Ms},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:Bo,e:Bo,f:jo,g:Mo,G:Ao,H:Io,I:Io,j:Lo,L:Po,m:Oo,M:Ro,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l.get(r[0].toLowerCase()),n+r[0].length):-1},q:Do,Q:zo,s:Uo,S:Fo,u:To,U:Eo,V:Co,w:ko,W:So,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:Mo,Y:Ao,Z:No,"%":Yo};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=lo(ho(a.y,0,1))).getUTCDay(),r=i>4||0===i?Ga.ceil(r):Ga(r),r=$a.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=uo(ho(a.y,0,1))).getDay(),r=i>4||0===i?Na.ceil(r):Na(r),r=Sa.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?lo(ho(a.y,0,1)).getUTCDay():uo(ho(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,lo(a)):uo(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in yo?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}),po=fo.format,fo.parse,fo.utcFormat,fo.utcParse;var Us=Array.prototype.find;function qs(){return this.firstElementChild}var Hs=Array.prototype.filter;function $s(){return Array.from(this.children)}function Ws(t){return new Array(t.length)}function Vs(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function Gs(t){return function(){return t}}function Xs(t,e,n,r,i,a){for(var o,s=0,c=e.length,u=a.length;se?1:t>=e?0:NaN}Vs.prototype={constructor:Vs,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var tc="http://www.w3.org/1999/xhtml";const ec={svg:"http://www.w3.org/2000/svg",xhtml:tc,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function nc(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),ec.hasOwnProperty(e)?{space:ec[e],local:t}:t}function rc(t){return function(){this.removeAttribute(t)}}function ic(t){return function(){this.removeAttributeNS(t.space,t.local)}}function ac(t,e){return function(){this.setAttribute(t,e)}}function oc(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function sc(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function cc(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function uc(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function lc(t){return function(){this.style.removeProperty(t)}}function hc(t,e,n){return function(){this.style.setProperty(t,e,n)}}function fc(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function dc(t,e){return t.style.getPropertyValue(e)||uc(t).getComputedStyle(t,null).getPropertyValue(e)}function pc(t){return function(){delete this[t]}}function yc(t,e){return function(){this[t]=e}}function gc(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function mc(t){return t.trim().split(/^|\s+/)}function vc(t){return t.classList||new bc(t)}function bc(t){this._node=t,this._names=mc(t.getAttribute("class")||"")}function _c(t,e){for(var n=vc(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function zc(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Wc=[null];function Vc(t,e){this._groups=t,this._parents=e}function Gc(){return new Vc([[document.documentElement]],Wc)}Vc.prototype=Gc.prototype={constructor:Vc,select:function(t){"function"!=typeof t&&(t=Rs(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=Js);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?lc:"function"==typeof e?fc:hc)(t,e,null==n?"":n)):dc(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?pc:"function"==typeof e?gc:yc)(t,e)):this.node()[t]},classed:function(t,e){var n=mc(t+"");if(arguments.length<2){for(var r=vc(this.node()),i=-1,a=n.length;++itu)if(Math.abs(l*s-c*u)>tu&&i){var f=n-a,d=r-o,p=s*s+c*c,y=f*f+d*d,g=Math.sqrt(p),m=Math.sqrt(h),v=i*Math.tan((Kc-Math.acos((p+h-y)/(2*g*m)))/2),b=v/m,_=v/g;Math.abs(b-1)>tu&&(this._+="L"+(t+b*u)+","+(e+b*l)),this._+="A"+i+","+i+",0,0,"+ +(l*f>u*d)+","+(this._x1=t+_*s)+","+(this._y1=e+_*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e)},arc:function(t,e,n,r,i,a){t=+t,e=+e,a=!!a;var o=(n=+n)*Math.cos(r),s=n*Math.sin(r),c=t+o,u=e+s,l=1^a,h=a?r-i:i-r;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+u:(Math.abs(this._x1-c)>tu||Math.abs(this._y1-u)>tu)&&(this._+="L"+c+","+u),n&&(h<0&&(h=h%Jc+Jc),h>eu?this._+="A"+n+","+n+",0,1,"+l+","+(t-o)+","+(e-s)+"A"+n+","+n+",0,1,"+l+","+(this._x1=c)+","+(this._y1=u):h>tu&&(this._+="A"+n+","+n+",0,"+ +(h>=Kc)+","+l+","+(this._x1=t+n*Math.cos(i))+","+(this._y1=e+n*Math.sin(i))))},rect:function(t,e,n,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};const iu=ru;function au(t){return function(){return t}}var ou=Math.abs,su=Math.atan2,cu=Math.cos,uu=Math.max,lu=Math.min,hu=Math.sin,fu=Math.sqrt,du=1e-12,pu=Math.PI,yu=pu/2,gu=2*pu;function mu(t){return t>1?0:t<-1?pu:Math.acos(t)}function vu(t){return t>=1?yu:t<=-1?-yu:Math.asin(t)}function bu(t){return t.innerRadius}function _u(t){return t.outerRadius}function xu(t){return t.startAngle}function wu(t){return t.endAngle}function ku(t){return t&&t.padAngle}function Tu(t,e,n,r,i,a,o,s){var c=n-t,u=r-e,l=o-i,h=s-a,f=h*c-l*u;if(!(f*fN*N+D*D&&(T=C,E=S),{cx:T,cy:E,x01:-l,y01:-h,x11:T*(i/x-1),y11:E*(i/x-1)}}function Cu(){var t=bu,e=_u,n=au(0),r=null,i=xu,a=wu,o=ku,s=null;function c(){var c,u,l=+t.apply(this,arguments),h=+e.apply(this,arguments),f=i.apply(this,arguments)-yu,d=a.apply(this,arguments)-yu,p=ou(d-f),y=d>f;if(s||(s=c=iu()),hdu)if(p>gu-du)s.moveTo(h*cu(f),h*hu(f)),s.arc(0,0,h,f,d,!y),l>du&&(s.moveTo(l*cu(d),l*hu(d)),s.arc(0,0,l,d,f,y));else{var g,m,v=f,b=d,_=f,x=d,w=p,k=p,T=o.apply(this,arguments)/2,E=T>du&&(r?+r.apply(this,arguments):fu(l*l+h*h)),C=lu(ou(h-l)/2,+n.apply(this,arguments)),S=C,A=C;if(E>du){var M=vu(E/l*hu(T)),N=vu(E/h*hu(T));(w-=2*M)>du?(_+=M*=y?1:-1,x-=M):(w=0,_=x=(f+d)/2),(k-=2*N)>du?(v+=N*=y?1:-1,b-=N):(k=0,v=b=(f+d)/2)}var D=h*cu(v),O=h*hu(v),B=l*cu(x),L=l*hu(x);if(C>du){var I,R=h*cu(b),F=h*hu(b),P=l*cu(_),j=l*hu(_);if(pdu?A>du?(g=Eu(P,j,D,O,h,A,y),m=Eu(R,F,B,L,h,A,y),s.moveTo(g.cx+g.x01,g.cy+g.y01),Adu&&w>du?S>du?(g=Eu(B,L,R,F,l,-S,y),m=Eu(D,O,P,j,l,-S,y),s.lineTo(g.cx+g.x01,g.cy+g.y01),St?1:e>=t?0:NaN}function Lu(t){return t}function Iu(){}function Ru(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function Fu(t){this._context=t}function Pu(t){return new Fu(t)}function ju(t){this._context=t}function Yu(t){this._context=t}function zu(t){this._context=t}function Uu(t){return t<0?-1:1}function qu(t,e,n){var r=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(r||i<0&&-0),o=(n-t._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(Uu(a)+Uu(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function Hu(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function $u(t,e,n){var r=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-r)/3;t._context.bezierCurveTo(r+s,i+s*e,a-s,o-s*n,a,o)}function Wu(t){this._context=t}function Vu(t){this._context=new Gu(t)}function Gu(t){this._context=t}function Xu(t){this._context=t}function Zu(t){var e,n,r=t.length-1,i=new Array(r),a=new Array(r),o=new Array(r);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var Ku=new Date,Ju=new Date;function tl(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return Ku.setTime(+e),Ju.setTime(+r),t(Ku),t(Ju),Math.floor(n(Ku,Ju))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}const el=6048e5;function nl(t){return tl((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/el}))}var rl=nl(0),il=nl(1),al=nl(2),ol=nl(3),sl=nl(4),cl=nl(5),ul=nl(6),ll=(rl.range,il.range,al.range,ol.range,sl.range,cl.range,ul.range,tl((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/864e5}),(function(t){return t.getUTCDate()-1})));const hl=ll;function fl(t){return tl((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/el}))}ll.range;var dl=fl(0),pl=fl(1),yl=fl(2),gl=fl(3),ml=fl(4),vl=fl(5),bl=fl(6),_l=(dl.range,pl.range,yl.range,gl.range,ml.range,vl.range,bl.range,tl(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/864e5,t=>t.getDate()-1));const xl=_l;_l.range;var wl=tl((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));wl.every=function(t){return isFinite(t=Math.floor(t))&&t>0?tl((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const kl=wl;wl.range;var Tl=tl((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Tl.every=function(t){return isFinite(t=Math.floor(t))&&t>0?tl((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const El=Tl;function Cl(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Sl(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Al(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}Tl.range;var Ml,Nl,Dl={"-":"",_:" ",0:"0"},Ol=/^\s*\d+/,Bl=/^%/,Ll=/[\\^$*+?|[\]().{}]/g;function Il(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",a=i.length;return r+(a[t.toLowerCase(),e]))}function jl(t,e,n){var r=Ol.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Yl(t,e,n){var r=Ol.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function zl(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Ul(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function ql(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function Hl(t,e,n){var r=Ol.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function $l(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function Wl(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Vl(t,e,n){var r=Ol.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function Gl(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Xl(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Zl(t,e,n){var r=Ol.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Ql(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function Kl(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Jl(t,e,n){var r=Ol.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function th(t,e,n){var r=Ol.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function eh(t,e,n){var r=Ol.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function nh(t,e,n){var r=Bl.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function rh(t,e,n){var r=Ol.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function ih(t,e,n){var r=Ol.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function ah(t,e){return Il(t.getDate(),e,2)}function oh(t,e){return Il(t.getHours(),e,2)}function sh(t,e){return Il(t.getHours()%12||12,e,2)}function ch(t,e){return Il(1+xl.count(kl(t),t),e,3)}function uh(t,e){return Il(t.getMilliseconds(),e,3)}function lh(t,e){return uh(t,e)+"000"}function hh(t,e){return Il(t.getMonth()+1,e,2)}function fh(t,e){return Il(t.getMinutes(),e,2)}function dh(t,e){return Il(t.getSeconds(),e,2)}function ph(t){var e=t.getDay();return 0===e?7:e}function yh(t,e){return Il(dl.count(kl(t)-1,t),e,2)}function gh(t){var e=t.getDay();return e>=4||0===e?ml(t):ml.ceil(t)}function mh(t,e){return t=gh(t),Il(ml.count(kl(t),t)+(4===kl(t).getDay()),e,2)}function vh(t){return t.getDay()}function bh(t,e){return Il(pl.count(kl(t)-1,t),e,2)}function _h(t,e){return Il(t.getFullYear()%100,e,2)}function xh(t,e){return Il((t=gh(t)).getFullYear()%100,e,2)}function wh(t,e){return Il(t.getFullYear()%1e4,e,4)}function kh(t,e){var n=t.getDay();return Il((t=n>=4||0===n?ml(t):ml.ceil(t)).getFullYear()%1e4,e,4)}function Th(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Il(e/60|0,"0",2)+Il(e%60,"0",2)}function Eh(t,e){return Il(t.getUTCDate(),e,2)}function Ch(t,e){return Il(t.getUTCHours(),e,2)}function Sh(t,e){return Il(t.getUTCHours()%12||12,e,2)}function Ah(t,e){return Il(1+hl.count(El(t),t),e,3)}function Mh(t,e){return Il(t.getUTCMilliseconds(),e,3)}function Nh(t,e){return Mh(t,e)+"000"}function Dh(t,e){return Il(t.getUTCMonth()+1,e,2)}function Oh(t,e){return Il(t.getUTCMinutes(),e,2)}function Bh(t,e){return Il(t.getUTCSeconds(),e,2)}function Lh(t){var e=t.getUTCDay();return 0===e?7:e}function Ih(t,e){return Il(rl.count(El(t)-1,t),e,2)}function Rh(t){var e=t.getUTCDay();return e>=4||0===e?sl(t):sl.ceil(t)}function Fh(t,e){return t=Rh(t),Il(sl.count(El(t),t)+(4===El(t).getUTCDay()),e,2)}function Ph(t){return t.getUTCDay()}function jh(t,e){return Il(il.count(El(t)-1,t),e,2)}function Yh(t,e){return Il(t.getUTCFullYear()%100,e,2)}function zh(t,e){return Il((t=Rh(t)).getUTCFullYear()%100,e,2)}function Uh(t,e){return Il(t.getUTCFullYear()%1e4,e,4)}function qh(t,e){var n=t.getUTCDay();return Il((t=n>=4||0===n?sl(t):sl.ceil(t)).getUTCFullYear()%1e4,e,4)}function Hh(){return"+0000"}function $h(){return"%"}function Wh(t){return+t}function Vh(t){return Math.floor(+t/1e3)}Ml=function(t){var e=t.dateTime,n=t.date,r=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,c=t.shortMonths,u=Fl(i),l=Pl(i),h=Fl(a),f=Pl(a),d=Fl(o),p=Pl(o),y=Fl(s),g=Pl(s),m=Fl(c),v=Pl(c),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:ah,e:ah,f:lh,g:xh,G:kh,H:oh,I:sh,j:ch,L:uh,m:hh,M:fh,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Wh,s:Vh,S:dh,u:ph,U:yh,V:mh,w:vh,W:bh,x:null,X:null,y:_h,Y:wh,Z:Th,"%":$h},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:Eh,e:Eh,f:Nh,g:zh,G:qh,H:Ch,I:Sh,j:Ah,L:Mh,m:Dh,M:Oh,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Wh,s:Vh,S:Bh,u:Lh,U:Ih,V:Fh,w:Ph,W:jh,x:null,X:null,y:Yh,Y:Uh,Z:Hh,"%":$h},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:Xl,e:Xl,f:eh,g:$l,G:Hl,H:Ql,I:Ql,j:Zl,L:th,m:Gl,M:Kl,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l.get(r[0].toLowerCase()),n+r[0].length):-1},q:Vl,Q:rh,s:ih,S:Jl,u:Yl,U:zl,V:Ul,w:jl,W:ql,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:$l,Y:Hl,Z:Wl,"%":nh};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=Sl(Al(a.y,0,1))).getUTCDay(),r=i>4||0===i?il.ceil(r):il(r),r=hl.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=Cl(Al(a.y,0,1))).getDay(),r=i>4||0===i?pl.ceil(r):pl(r),r=xl.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?Sl(Al(a.y,0,1)).getUTCDay():Cl(Al(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,Sl(a)):Cl(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in Dl?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}),Nl=Ml.format,Ml.parse,Ml.utcFormat,Ml.utcParse;var Gh={value:()=>{}};function Xh(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function Kh(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--rf}()}finally{rf=0,function(){for(var t,e,n=ef,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:ef=e);nf=t,vf(r)}(),cf=0}}function mf(){var t=lf.now(),e=t-sf;e>1e3&&(uf-=e,sf=t)}function vf(t){rf||(af&&(af=clearTimeout(af)),t-cf>24?(t<1/0&&(af=setTimeout(gf,t-lf.now()-uf)),of&&(of=clearInterval(of))):(of||(sf=lf.now(),of=setInterval(mf,1e3)),rf=1,hf(gf)))}function bf(t,e,n){var r=new pf;return e=null==e?0:+e,r.restart(n=>{r.stop(),t(n+e)},e,n),r}pf.prototype=yf.prototype={constructor:pf,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?ff():+n)+(null==e?0:+e),this._next||nf===this||(nf?nf._next=this:ef=this,nf=this),this._call=t,this._time=n,vf()},stop:function(){this._call&&(this._call=null,this._time=1/0,vf())}};var _f=tf("start","end","cancel","interrupt"),xf=[];function wf(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return bf(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function Tf(t,e){var n=Ef(t,e);if(n.state>3)throw new Error("too late; already running");return n}function Ef(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function Cf(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var Sf,Af=180/Math.PI,Mf={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Nf(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:Cf(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:Cf(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:Cf(t,n)},{i:s-2,x:Cf(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:Cf(n,r)})),a=zf.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?kf:Tf;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var od=Xc.prototype.constructor;function sd(t){return function(){this.style.removeProperty(t)}}function cd(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function ud(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&cd(t,a,n)),r}return a._value=e,a}function ld(t){return function(e){this.textContent=t.call(this,e)}}function hd(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&ld(r)),e}return r._value=t,r}var fd=0;function dd(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function pd(){return++fd}var yd=Xc.prototype;dd.prototype=function(t){return Xc().transition(t)}.prototype={constructor:dd,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=Rs(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Xc.prototype.transition=function(t){var e,n;t instanceof dd?(e=t._id,t=t._name):(e=pd(),(n=gd).time=ff(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;ae?1:t>=e?0:NaN}Nd.prototype={constructor:Nd,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var Fd="http://www.w3.org/1999/xhtml";const Pd={svg:"http://www.w3.org/2000/svg",xhtml:Fd,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function jd(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Pd.hasOwnProperty(e)?{space:Pd[e],local:t}:t}function Yd(t){return function(){this.removeAttribute(t)}}function zd(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Ud(t,e){return function(){this.setAttribute(t,e)}}function qd(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function Hd(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function $d(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Wd(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Vd(t){return function(){this.style.removeProperty(t)}}function Gd(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Xd(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Zd(t,e){return t.style.getPropertyValue(e)||Wd(t).getComputedStyle(t,null).getPropertyValue(e)}function Qd(t){return function(){delete this[t]}}function Kd(t,e){return function(){this[t]=e}}function Jd(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function tp(t){return t.trim().split(/^|\s+/)}function ep(t){return t.classList||new np(t)}function np(t){this._node=t,this._names=tp(t.getAttribute("class")||"")}function rp(t,e){for(var n=ep(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function Tp(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Mp=[null];function Np(t,e){this._groups=t,this._parents=e}function Dp(){return new Np([[document.documentElement]],Mp)}Np.prototype=Dp.prototype={constructor:Np,select:function(t){"function"!=typeof t&&(t=bd(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=Rd);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?Vd:"function"==typeof e?Xd:Gd)(t,e,null==n?"":n)):Zd(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Qd:"function"==typeof e?Jd:Kd)(t,e)):this.node()[t]},classed:function(t,e){var n=tp(t+"");if(arguments.length<2){for(var r=ep(this.node()),i=-1,a=n.length;++i{}};function Lp(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function Fp(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--Up}()}finally{Up=0,function(){for(var t,e,n=Yp,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:Yp=e);zp=t,ny(r)}(),Wp=0}}function ey(){var t=Gp.now(),e=t-$p;e>1e3&&(Vp-=e,$p=t)}function ny(t){Up||(qp&&(qp=clearTimeout(qp)),t-Wp>24?(t<1/0&&(qp=setTimeout(ty,t-Gp.now()-Vp)),Hp&&(Hp=clearInterval(Hp))):(Hp||($p=Gp.now(),Hp=setInterval(ey,1e3)),Up=1,Xp(ty)))}function ry(t,e,n){var r=new Kp;return e=null==e?0:+e,r.restart(n=>{r.stop(),t(n+e)},e,n),r}Kp.prototype=Jp.prototype={constructor:Kp,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Zp():+n)+(null==e?0:+e),this._next||zp===this||(zp?zp._next=this:Yp=this,zp=this),this._call=t,this._time=n,ny()},stop:function(){this._call&&(this._call=null,this._time=1/0,ny())}};var iy=jp("start","end","cancel","interrupt"),ay=[];function oy(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return ry(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function cy(t,e){var n=uy(t,e);if(n.state>3)throw new Error("too late; already running");return n}function uy(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function ly(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var hy,fy=180/Math.PI,dy={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function py(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:ly(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:ly(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:ly(t,n)},{i:s-2,x:ly(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Yy(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Yy(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=My.exec(t))?new qy(e[1],e[2],e[3],1):(e=Ny.exec(t))?new qy(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Dy.exec(t))?Yy(e[1],e[2],e[3],e[4]):(e=Oy.exec(t))?Yy(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=By.exec(t))?Vy(e[1],e[2]/100,e[3]/100,1):(e=Ly.exec(t))?Vy(e[1],e[2]/100,e[3]/100,e[4]):Iy.hasOwnProperty(t)?jy(Iy[t]):"transparent"===t?new qy(NaN,NaN,NaN,0):null}function jy(t){return new qy(t>>16&255,t>>8&255,255&t,1)}function Yy(t,e,n,r){return r<=0&&(t=e=n=NaN),new qy(t,e,n,r)}function zy(t){return t instanceof ky||(t=Py(t)),t?new qy((t=t.rgb()).r,t.g,t.b,t.opacity):new qy}function Uy(t,e,n,r){return 1===arguments.length?zy(t):new qy(t,e,n,null==r?1:r)}function qy(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Hy(){return"#"+Wy(this.r)+Wy(this.g)+Wy(this.b)}function $y(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function Wy(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Vy(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Xy(t,e,n,r)}function Gy(t){if(t instanceof Xy)return new Xy(t.h,t.s,t.l,t.opacity);if(t instanceof ky||(t=Py(t)),!t)return new Xy;if(t instanceof Xy)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new Xy(o,s,c,t.opacity)}function Xy(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function Zy(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function Qy(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}xy(ky,Py,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:Ry,formatHex:Ry,formatHsl:function(){return Gy(this).formatHsl()},formatRgb:Fy,toString:Fy}),xy(qy,Uy,wy(ky,{brighter:function(t){return t=null==t?Ty:Math.pow(Ty,t),new qy(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new qy(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Hy,formatHex:Hy,formatRgb:$y,toString:$y})),xy(Xy,(function(t,e,n,r){return 1===arguments.length?Gy(t):new Xy(t,e,n,null==r?1:r)}),wy(ky,{brighter:function(t){return t=null==t?Ty:Math.pow(Ty,t),new Xy(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Xy(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new qy(Zy(t>=240?t-240:t+120,i,r),Zy(t,i,r),Zy(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const Ky=t=>()=>t;function Jy(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):Ky(isNaN(t)?e:t)}const tg=function t(e){var n=function(t){return 1==(t=+t)?Jy:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):Ky(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=Uy(t)).r,(e=Uy(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=Jy(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function eg(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:ly(n,r)})),a=rg.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?sy:cy;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var wg=Op.prototype.constructor;function kg(t){return function(){this.style.removeProperty(t)}}function Tg(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function Eg(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Tg(t,a,n)),r}return a._value=e,a}function Cg(t){return function(e){this.textContent=t.call(this,e)}}function Sg(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&Cg(r)),e}return r._value=t,r}var Ag=0;function Mg(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function Ng(){return++Ag}var Dg=Op.prototype;Mg.prototype=function(t){return Op().transition(t)}.prototype={constructor:Mg,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=bd(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Op.prototype.transition=function(t){var e,n;t instanceof Mg?(e=t._id,t=t._name):(e=Ng(),(n=Og).time=Zp(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;a2||im(Qg)>3?"":" "}function sm(t,e){for(;--e&&tm()&&!(Qg<48||Qg>102||Qg>57&&Qg<65||Qg>70&&Qg<97););return rm(t,nm()+(e<6&&32==em()&&32==tm()))}function cm(t,e){for(;tm()&&t+Qg!==57&&(t+Qg!==84||47!==em()););return"/*"+rm(e,Zg-1)+"*"+Rg(47===t?t:tm())}function um(t){for(;!im(em());)tm();return rm(t,Zg)}function lm(t){return function(t){return Kg="",t}(function t(e,n,r,i,a,o,s,c,u){for(var l=0,h=0,f=s,d=0,p=0,y=0,g=1,m=1,v=1,b=0,_="",x=a,w=o,k=i,T=_;m;)switch(y=b,b=tm()){case 40:if(108!=y&&58==T.charCodeAt(f-1)){-1!=jg(T+=Pg(am(b),"&","&\f"),"&\f")&&(v=-1);break}case 34:case 39:case 91:T+=am(b);break;case 9:case 10:case 13:case 32:T+=om(y);break;case 92:T+=sm(nm()-1,7);continue;case 47:switch(em()){case 42:case 47:Hg(fm(cm(tm(),nm()),n,r),u);break;default:T+="/"}break;case 123*g:c[l++]=Ug(T)*v;case 125*g:case 59:case 0:switch(b){case 0:case 125:m=0;case 59+h:p>0&&Ug(T)-f&&Hg(p>32?dm(T+";",i,r,f-1):dm(Pg(T," ","")+";",i,r,f-2),u);break;case 59:T+=";";default:if(Hg(k=hm(T,n,r,l,h,a,c,_,x=[],w=[],f),o),123===b)if(0===h)t(T,n,k,k,x,o,f,c,w);else switch(d){case 100:case 109:case 115:t(e,k,k,i&&Hg(hm(e,k,k,0,0,a,c,_,a,x=[],f),w),a,w,f,c,i?x:w);break;default:t(T,k,k,k,[""],w,0,c,w)}}l=h=p=0,g=v=1,_=T="",f=s;break;case 58:f=1+Ug(T),p=y;default:if(g<1)if(123==b)--g;else if(125==b&&0==g++&&125==(Qg=Zg>0?Yg(Kg,--Zg):0,Gg--,10===Qg&&(Gg=1,Vg--),Qg))continue;switch(T+=Rg(b),b*g){case 38:v=h>0?1:(T+="\f",-1);break;case 44:c[l++]=(Ug(T)-1)*v,v=1;break;case 64:45===em()&&(T+=am(tm())),d=em(),h=f=Ug(_=T+=um(nm())),b++;break;case 45:45===y&&2==Ug(T)&&(g=0)}}return o}("",null,null,null,[""],t=function(t){return Vg=Gg=1,Xg=Ug(Kg=t),Zg=0,[]}(t),0,[0],t))}function hm(t,e,n,r,i,a,o,s,c,u,l){for(var h=i-1,f=0===i?a:[""],d=qg(f),p=0,y=0,g=0;p0?f[m]+" "+v:Pg(v,/&\f/g,f[m])))&&(c[g++]=b);return Jg(t,e,n,0===i?"rule":s,c,u,l)}function fm(t,e,n){return Jg(t,e,n,"comm",Rg(Qg),zg(t,2,-2),0)}function dm(t,e,n,r){return Jg(t,e,n,"decl",zg(t,0,r),zg(t,r+1,-1),r)}var pm=n(9609),ym=n(7856),gm=n.n(ym),mm=function(t){var e=t.replace(/\\u[\dA-F]{4}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\u/g,""),16))}));return(e=(e=e.replace(/\\x([0-9a-f]{2})/gi,(function(t,e){return String.fromCharCode(parseInt(e,16))}))).replace(/\\[\d\d\d]{3}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))).replace(/\\[\d\d\d]{2}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))},vm=function(t){for(var e="",n=0;n>=0;){if(!((n=t.indexOf("=0)){e+=t,n=-1;break}e+=t.substr(0,n),(n=(t=t.substr(n+1)).indexOf("<\/script>"))>=0&&(n+=9,t=t.substr(n))}var r=mm(e);return(r=(r=(r=r.replace(/script>/gi,"#")).replace(/javascript:/gi,"#")).replace(/onerror=/gi,"onerror:")).replace(/')}if(void 0!==n)switch(y){case"flowchart":case"flowchart-v2":n(T,I_.bindFunctions);break;case"gantt":n(T,Fx.bindFunctions);break;case"class":case"classDiagram":n(T,Vv.bindFunctions);break;default:n(T)}else o.debug("CB = undefined!");mk.forEach((function(t){t()})),mk=[];var S="sandbox"===s.securityLevel?"#i"+t:"#d"+t,A=Zc(S).node();return null!==A&&"function"==typeof A.remove&&Zc(S).node().remove(),T},parse:function(t){var e=Av(),n=bv.detectInit(t,e);n&&o.debug("reinit ",n);var r,i=bv.detectType(t,e);switch(o.debug("Type "+i),i){case"git":(r=rw()).parser.yy=tw;break;case"flowchart":case"flowchart-v2":I_.clear(),(r=F_()).parser.yy=I_;break;case"sequence":(r=Gw()).parser.yy=gk;break;case"gantt":(r=zx()).parser.yy=Fx;break;case"class":case"classDiagram":(r=Jv()).parser.yy=Vv;break;case"state":case"stateDiagram":(r=Vk()).parser.yy=sT;break;case"info":o.debug("info info info"),(r=vw()).parser.yy=gw;break;case"pie":o.debug("pie"),(r=ww()).parser.yy=Cw;break;case"er":o.debug("er"),(r=r_()).parser.yy=e_;break;case"journey":o.debug("Journey"),(r=BT()).parser.yy=DT;break;case"requirement":case"requirementDiagram":o.debug("RequirementDiagram"),(r=Dw()).parser.yy=Fw}return r.parser.yy.graphType=i,r.parser.yy.parseError=function(t,e){throw{str:t,hash:e}},r.parse(t),r},parseDirective:function(t,e,n,r){try{if(void 0!==e)switch(e=e.trim(),n){case"open_directive":eE={};break;case"type_directive":eE.type=e.toLowerCase();break;case"arg_directive":eE.args=JSON.parse(e);break;case"close_directive":(function(t,e,n){switch(o.debug("Directive type=".concat(e.type," with args:"),e.args),e.type){case"init":case"initialize":["config"].forEach((function(t){void 0!==e.args[t]&&("flowchart-v2"===n&&(n="flowchart"),e.args[n]=e.args[t],delete e.args[t])})),o.debug("sanitize in handleDirective",e.args),mv(e.args),o.debug("sanitize in handleDirective (done)",e.args),e.args,Nv(e.args);break;case"wrap":case"nowrap":t&&t.setWrap&&t.setWrap("wrap"===e.type);break;case"themeCss":o.warn("themeCss encountered");break;default:o.warn("Unhandled directive: source: '%%{".concat(e.type,": ").concat(JSON.stringify(e.args?e.args:{}),"}%%"),e)}})(t,eE,r),eE=null}}catch(t){o.error("Error while rendering sequenceDiagram directive: ".concat(e," jison context: ").concat(n)),o.error(t.message)}},initialize:function(t){t&&t.fontFamily&&(t.themeVariables&&t.themeVariables.fontFamily||(t.themeVariables={fontFamily:t.fontFamily})),function(t){xv=uv({},t)}(t),t&&t.theme&&Fm[t.theme]?t.themeVariables=Fm[t.theme].getThemeVariables(t.themeVariables):t&&(t.themeVariables=Fm.default.getThemeVariables(t.themeVariables));var e="object"===JT(t)?function(t){return kv=uv({},wv),kv=uv(kv,t),t.theme&&(kv.themeVariables=Fm[t.theme].getThemeVariables(t.themeVariables)),Ev=Cv(kv,Tv),kv}(t):Sv();nE(e),s(e.logLevel)},reinitialize:function(){},getConfig:Av,setConfig:function(t){return uv(Ev,t),Av()},getSiteConfig:Sv,updateSiteConfig:function(t){return kv=uv(kv,t),Cv(kv,Tv),kv},reset:function(){Dv()},globalReset:function(){Dv(),nE(Av())},defaultConfig:wv});s(Av().logLevel),Dv(Av());const iE=rE;var aE=function(){oE.startOnLoad?iE.getConfig().startOnLoad&&oE.init():void 0===oE.startOnLoad&&(o.debug("In start, no config"),iE.getConfig().startOnLoad&&oE.init())};"undefined"!=typeof document&&window.addEventListener("load",(function(){aE()}),!1);var oE={startOnLoad:!0,htmlLabels:!0,mermaidAPI:iE,parse:iE.parse,render:iE.render,init:function(){var t,e,n=this,r=iE.getConfig();arguments.length>=2?(void 0!==arguments[0]&&(oE.sequenceConfig=arguments[0]),t=arguments[1]):t=arguments[0],"function"==typeof arguments[arguments.length-1]?(e=arguments[arguments.length-1],o.debug("Callback function found")):void 0!==r.mermaid&&("function"==typeof r.mermaid.callback?(e=r.mermaid.callback,o.debug("Callback function found")):o.debug("No Callback function found")),t=void 0===t?document.querySelectorAll(".mermaid"):"string"==typeof t?document.querySelectorAll(t):t instanceof window.Node?[t]:t,o.debug("Start On Load before: "+oE.startOnLoad),void 0!==oE.startOnLoad&&(o.debug("Start On Load inner: "+oE.startOnLoad),iE.updateSiteConfig({startOnLoad:oE.startOnLoad})),void 0!==oE.ganttConfig&&iE.updateSiteConfig({gantt:oE.ganttConfig});for(var i,a=new bv.initIdGeneratior(r.deterministicIds,r.deterministicIDSeed),s=function(r){var s=t[r];if(s.getAttribute("data-processed"))return"continue";s.setAttribute("data-processed",!0);var c="mermaid-".concat(a.next());i=s.innerHTML,i=bv.entityDecode(i).trim().replace(//gi,"
");var u=bv.detectInit(i);u&&o.debug("Detected early reinit: ",u);try{iE.render(c,i,(function(t,n){s.innerHTML=t,void 0!==e&&e(c),n&&n(s)}),s)}catch(t){o.warn("Syntax Error rendering"),o.warn(t),n.parseError&&n.parseError(t)}},c=0;c{t.exports={graphlib:n(6614),dagre:n(1463),intersect:n(8114),render:n(5787),util:n(8355),version:n(5689)}},9144:(t,e,n)=>{var r=n(8355);function i(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])}t.exports={default:i,normal:i,vee:function(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 L 4 5 z").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])},undirected:function(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 5 L 10 5").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])}}},5632:(t,e,n)=>{var r=n(8355),i=n(4322),a=n(1322);t.exports=function(t,e){var n,o=e.nodes().filter((function(t){return r.isSubgraph(e,t)})),s=t.selectAll("g.cluster").data(o,(function(t){return t}));return s.selectAll("*").remove(),s.enter().append("g").attr("class","cluster").attr("id",(function(t){return e.node(t).id})).style("opacity",0),s=t.selectAll("g.cluster"),r.applyTransition(s,e).style("opacity",1),s.each((function(t){var n=e.node(t),r=i.select(this);i.select(this).append("rect");var o=r.append("g").attr("class","label");a(o,n,n.clusterLabelPos)})),s.selectAll("rect").each((function(t){var n=e.node(t),a=i.select(this);r.applyStyle(a,n.style)})),n=s.exit?s.exit():s.selectAll(null),r.applyTransition(n,e).style("opacity",0).remove(),s}},6315:(t,e,n)=>{"use strict";var r=n(1034),i=n(1322),a=n(8355),o=n(4322);t.exports=function(t,e){var n,s=t.selectAll("g.edgeLabel").data(e.edges(),(function(t){return a.edgeToId(t)})).classed("update",!0);return s.exit().remove(),s.enter().append("g").classed("edgeLabel",!0).style("opacity",0),(s=t.selectAll("g.edgeLabel")).each((function(t){var n=o.select(this);n.select(".label").remove();var a=e.edge(t),s=i(n,e.edge(t),0,0).classed("label",!0),c=s.node().getBBox();a.labelId&&s.attr("id",a.labelId),r.has(a,"width")||(a.width=c.width),r.has(a,"height")||(a.height=c.height)})),n=s.exit?s.exit():s.selectAll(null),a.applyTransition(n,e).style("opacity",0).remove(),s}},940:(t,e,n)=>{"use strict";var r=n(1034),i=n(7584),a=n(8355),o=n(4322);function s(t,e){var n=(o.line||o.svg.line)().x((function(t){return t.x})).y((function(t){return t.y}));return(n.curve||n.interpolate)(t.curve),n(e)}t.exports=function(t,e,n){var c=t.selectAll("g.edgePath").data(e.edges(),(function(t){return a.edgeToId(t)})).classed("update",!0),u=function(t,e){var n=t.enter().append("g").attr("class","edgePath").style("opacity",0);return n.append("path").attr("class","path").attr("d",(function(t){var n=e.edge(t),i=e.node(t.v).elem;return s(n,r.range(n.points.length).map((function(){return e=(t=i).getBBox(),{x:(n=t.ownerSVGElement.getScreenCTM().inverse().multiply(t.getScreenCTM()).translate(e.width/2,e.height/2)).e,y:n.f};var t,e,n})))})),n.append("defs"),n}(c,e);!function(t,e){var n=t.exit();a.applyTransition(n,e).style("opacity",0).remove()}(c,e);var l=void 0!==c.merge?c.merge(u):c;return a.applyTransition(l,e).style("opacity",1),l.each((function(t){var n=o.select(this),r=e.edge(t);r.elem=this,r.id&&n.attr("id",r.id),a.applyClass(n,r.class,(n.classed("update")?"update ":"")+"edgePath")})),l.selectAll("path.path").each((function(t){var n=e.edge(t);n.arrowheadId=r.uniqueId("arrowhead");var c=o.select(this).attr("marker-end",(function(){return"url("+(t=location.href,e=n.arrowheadId,t.split("#")[0]+"#"+e+")");var t,e})).style("fill","none");a.applyTransition(c,e).attr("d",(function(t){return function(t,e){var n=t.edge(e),r=t.node(e.v),a=t.node(e.w),o=n.points.slice(1,n.points.length-1);return o.unshift(i(r,o[0])),o.push(i(a,o[o.length-1])),s(n,o)}(e,t)})),a.applyStyle(c,n.style)})),l.selectAll("defs *").remove(),l.selectAll("defs").each((function(t){var r=e.edge(t);(0,n[r.arrowhead])(o.select(this),r.arrowheadId,r,"arrowhead")})),l}},607:(t,e,n)=>{"use strict";var r=n(1034),i=n(1322),a=n(8355),o=n(4322);t.exports=function(t,e,n){var s,c=e.nodes().filter((function(t){return!a.isSubgraph(e,t)})),u=t.selectAll("g.node").data(c,(function(t){return t})).classed("update",!0);return u.exit().remove(),u.enter().append("g").attr("class","node").style("opacity",0),(u=t.selectAll("g.node")).each((function(t){var s=e.node(t),c=o.select(this);a.applyClass(c,s.class,(c.classed("update")?"update ":"")+"node"),c.select("g.label").remove();var u=c.append("g").attr("class","label"),l=i(u,s),h=n[s.shape],f=r.pick(l.node().getBBox(),"width","height");s.elem=this,s.id&&c.attr("id",s.id),s.labelId&&u.attr("id",s.labelId),r.has(s,"width")&&(f.width=s.width),r.has(s,"height")&&(f.height=s.height),f.width+=s.paddingLeft+s.paddingRight,f.height+=s.paddingTop+s.paddingBottom,u.attr("transform","translate("+(s.paddingLeft-s.paddingRight)/2+","+(s.paddingTop-s.paddingBottom)/2+")");var d=o.select(this);d.select(".label-container").remove();var p=h(d,f,s).classed("label-container",!0);a.applyStyle(p,s.style);var y=p.node().getBBox();s.width=y.width,s.height=y.height})),s=u.exit?u.exit():u.selectAll(null),a.applyTransition(s,e).style("opacity",0).remove(),u}},4322:(t,e,n)=>{var r;if(!r)try{r=n(7188)}catch(t){}r||(r=window.d3),t.exports=r},1463:(t,e,n)=>{var r;try{r=n(681)}catch(t){}r||(r=window.dagre),t.exports=r},6614:(t,e,n)=>{var r;try{r=n(8282)}catch(t){}r||(r=window.graphlib),t.exports=r},8114:(t,e,n)=>{t.exports={node:n(7584),circle:n(6587),ellipse:n(3260),polygon:n(5337),rect:n(8049)}},6587:(t,e,n)=>{var r=n(3260);t.exports=function(t,e,n){return r(t,e,e,n)}},3260:t=>{t.exports=function(t,e,n,r){var i=t.x,a=t.y,o=i-r.x,s=a-r.y,c=Math.sqrt(e*e*s*s+n*n*o*o),u=Math.abs(e*n*o/c);r.x{function e(t,e){return t*e>0}t.exports=function(t,n,r,i){var a,o,s,c,u,l,h,f,d,p,y,g,m;if(a=n.y-t.y,s=t.x-n.x,u=n.x*t.y-t.x*n.y,d=a*r.x+s*r.y+u,p=a*i.x+s*i.y+u,!(0!==d&&0!==p&&e(d,p)||(o=i.y-r.y,c=r.x-i.x,l=i.x*r.y-r.x*i.y,h=o*t.x+c*t.y+l,f=o*n.x+c*n.y+l,0!==h&&0!==f&&e(h,f)||0==(y=a*c-o*s))))return g=Math.abs(y/2),{x:(m=s*l-c*u)<0?(m-g)/y:(m+g)/y,y:(m=o*u-a*l)<0?(m-g)/y:(m+g)/y}}},7584:t=>{t.exports=function(t,e){return t.intersect(e)}},5337:(t,e,n)=>{var r=n(6808);t.exports=function(t,e,n){var i=t.x,a=t.y,o=[],s=Number.POSITIVE_INFINITY,c=Number.POSITIVE_INFINITY;e.forEach((function(t){s=Math.min(s,t.x),c=Math.min(c,t.y)}));for(var u=i-t.width/2-s,l=a-t.height/2-c,h=0;h1&&o.sort((function(t,e){var r=t.x-n.x,i=t.y-n.y,a=Math.sqrt(r*r+i*i),o=e.x-n.x,s=e.y-n.y,c=Math.sqrt(o*o+s*s);return a{t.exports=function(t,e){var n,r,i=t.x,a=t.y,o=e.x-i,s=e.y-a,c=t.width/2,u=t.height/2;return Math.abs(s)*c>Math.abs(o)*u?(s<0&&(u=-u),n=0===s?0:u*o/s,r=u):(o<0&&(c=-c),n=c,r=0===o?0:c*s/o),{x:i+n,y:a+r}}},8284:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){var n=t.append("foreignObject").attr("width","100000"),i=n.append("xhtml:div");i.attr("xmlns","http://www.w3.org/1999/xhtml");var a=e.label;switch(typeof a){case"function":i.insert(a);break;case"object":i.insert((function(){return a}));break;default:i.html(a)}r.applyStyle(i,e.labelStyle),i.style("display","inline-block"),i.style("white-space","nowrap");var o=i.node().getBoundingClientRect();return n.attr("width",o.width).attr("height",o.height),n}},1322:(t,e,n)=>{var r=n(7318),i=n(8284),a=n(8287);t.exports=function(t,e,n){var o=e.label,s=t.append("g");"svg"===e.labelType?a(s,e):"string"!=typeof o||"html"===e.labelType?i(s,e):r(s,e);var c,u=s.node().getBBox();switch(n){case"top":c=-e.height/2;break;case"bottom":c=e.height/2-u.height;break;default:c=-u.height/2}return s.attr("transform","translate("+-u.width/2+","+c+")"),s}},8287:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){var n=t;return n.node().appendChild(e.label),r.applyStyle(n,e.labelStyle),n}},7318:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){for(var n=t.append("text"),i=function(t){for(var e,n="",r=!1,i=0;i{var r;try{r={defaults:n(1747),each:n(6073),isFunction:n(3560),isPlainObject:n(8630),pick:n(9722),has:n(8721),range:n(6026),uniqueId:n(3955)}}catch(t){}r||(r=window._),t.exports=r},6381:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322);t.exports=function(t,e){var n=t.filter((function(){return!i.select(this).classed("update")}));function a(t){var n=e.node(t);return"translate("+n.x+","+n.y+")"}n.attr("transform",a),r.applyTransition(t,e).style("opacity",1).attr("transform",a),r.applyTransition(n.selectAll("rect"),e).attr("width",(function(t){return e.node(t).width})).attr("height",(function(t){return e.node(t).height})).attr("x",(function(t){return-e.node(t).width/2})).attr("y",(function(t){return-e.node(t).height/2}))}},4577:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322),a=n(1034);t.exports=function(t,e){function n(t){var n=e.edge(t);return a.has(n,"x")?"translate("+n.x+","+n.y+")":""}t.filter((function(){return!i.select(this).classed("update")})).attr("transform",n),r.applyTransition(t,e).style("opacity",1).attr("transform",n)}},4849:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322);t.exports=function(t,e){function n(t){var n=e.node(t);return"translate("+n.x+","+n.y+")"}t.filter((function(){return!i.select(this).classed("update")})).attr("transform",n),r.applyTransition(t,e).style("opacity",1).attr("transform",n)}},5787:(t,e,n)=>{var r=n(1034),i=n(4322),a=n(1463).layout;t.exports=function(){var t=n(607),e=n(5632),i=n(6315),u=n(940),l=n(4849),h=n(4577),f=n(6381),d=n(4418),p=n(9144),y=function(n,y){!function(t){t.nodes().forEach((function(e){var n=t.node(e);r.has(n,"label")||t.children(e).length||(n.label=e),r.has(n,"paddingX")&&r.defaults(n,{paddingLeft:n.paddingX,paddingRight:n.paddingX}),r.has(n,"paddingY")&&r.defaults(n,{paddingTop:n.paddingY,paddingBottom:n.paddingY}),r.has(n,"padding")&&r.defaults(n,{paddingLeft:n.padding,paddingRight:n.padding,paddingTop:n.padding,paddingBottom:n.padding}),r.defaults(n,o),r.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],(function(t){n[t]=Number(n[t])})),r.has(n,"width")&&(n._prevWidth=n.width),r.has(n,"height")&&(n._prevHeight=n.height)})),t.edges().forEach((function(e){var n=t.edge(e);r.has(n,"label")||(n.label=""),r.defaults(n,s)}))}(y);var g=c(n,"output"),m=c(g,"clusters"),v=c(g,"edgePaths"),b=i(c(g,"edgeLabels"),y),_=t(c(g,"nodes"),y,d);a(y),l(_,y),h(b,y),u(v,y,p);var x=e(m,y);f(x,y),function(t){r.each(t.nodes(),(function(e){var n=t.node(e);r.has(n,"_prevWidth")?n.width=n._prevWidth:delete n.width,r.has(n,"_prevHeight")?n.height=n._prevHeight:delete n.height,delete n._prevWidth,delete n._prevHeight}))}(y)};return y.createNodes=function(e){return arguments.length?(t=e,y):t},y.createClusters=function(t){return arguments.length?(e=t,y):e},y.createEdgeLabels=function(t){return arguments.length?(i=t,y):i},y.createEdgePaths=function(t){return arguments.length?(u=t,y):u},y.shapes=function(t){return arguments.length?(d=t,y):d},y.arrows=function(t){return arguments.length?(p=t,y):p},y};var o={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},s={arrowhead:"normal",curve:i.curveLinear};function c(t,e){var n=t.select("g."+e);return n.empty()&&(n=t.append("g").attr("class",e)),n}},4418:(t,e,n)=>{"use strict";var r=n(8049),i=n(3260),a=n(6587),o=n(5337);t.exports={rect:function(t,e,n){var i=t.insert("rect",":first-child").attr("rx",n.rx).attr("ry",n.ry).attr("x",-e.width/2).attr("y",-e.height/2).attr("width",e.width).attr("height",e.height);return n.intersect=function(t){return r(n,t)},i},ellipse:function(t,e,n){var r=e.width/2,a=e.height/2,o=t.insert("ellipse",":first-child").attr("x",-e.width/2).attr("y",-e.height/2).attr("rx",r).attr("ry",a);return n.intersect=function(t){return i(n,r,a,t)},o},circle:function(t,e,n){var r=Math.max(e.width,e.height)/2,i=t.insert("circle",":first-child").attr("x",-e.width/2).attr("y",-e.height/2).attr("r",r);return n.intersect=function(t){return a(n,r,t)},i},diamond:function(t,e,n){var r=e.width*Math.SQRT2/2,i=e.height*Math.SQRT2/2,a=[{x:0,y:-i},{x:-r,y:0},{x:0,y:i},{x:r,y:0}],s=t.insert("polygon",":first-child").attr("points",a.map((function(t){return t.x+","+t.y})).join(" "));return n.intersect=function(t){return o(n,a,t)},s}}},8355:(t,e,n)=>{var r=n(1034);t.exports={isSubgraph:function(t,e){return!!t.children(e).length},edgeToId:function(t){return a(t.v)+":"+a(t.w)+":"+a(t.name)},applyStyle:function(t,e){e&&t.attr("style",e)},applyClass:function(t,e,n){e&&t.attr("class",e).attr("class",n+" "+t.attr("class"))},applyTransition:function(t,e){var n=e.graph();if(r.isPlainObject(n)){var i=n.transition;if(r.isFunction(i))return i(t)}return t}};var i=/:/g;function a(t){return t?String(t).replace(i,"\\:"):""}},5689:t=>{t.exports="0.6.4"},7188:(t,e,n)=>{"use strict";n.r(e),n.d(e,{FormatSpecifier:()=>rc,active:()=>Kr,arc:()=>rx,area:()=>ux,areaRadial:()=>vx,ascending:()=>i,autoType:()=>Do,axisBottom:()=>it,axisLeft:()=>at,axisRight:()=>rt,axisTop:()=>nt,bisect:()=>u,bisectLeft:()=>c,bisectRight:()=>s,bisector:()=>a,blob:()=>hs,brush:()=>Si,brushSelection:()=>Ti,brushX:()=>Ei,brushY:()=>Ci,buffer:()=>ds,chord:()=>Ri,clientPoint:()=>Nn,cluster:()=>_d,color:()=>We,contourDensity:()=>to,contours:()=>Ga,create:()=>N_,creator:()=>ie,cross:()=>f,csv:()=>vs,csvFormat:()=>vo,csvFormatBody:()=>bo,csvFormatRow:()=>xo,csvFormatRows:()=>_o,csvFormatValue:()=>wo,csvParse:()=>go,csvParseRows:()=>mo,cubehelix:()=>Pa,curveBasis:()=>Kx,curveBasisClosed:()=>tw,curveBasisOpen:()=>nw,curveBundle:()=>iw,curveCardinal:()=>sw,curveCardinalClosed:()=>uw,curveCardinalOpen:()=>hw,curveCatmullRom:()=>pw,curveCatmullRomClosed:()=>gw,curveCatmullRomOpen:()=>vw,curveLinear:()=>ax,curveLinearClosed:()=>_w,curveMonotoneX:()=>Aw,curveMonotoneY:()=>Mw,curveNatural:()=>Ow,curveStep:()=>Lw,curveStepAfter:()=>Rw,curveStepBefore:()=>Iw,customEvent:()=>ge,descending:()=>d,deviation:()=>g,dispatch:()=>ft,drag:()=>so,dragDisable:()=>Se,dragEnable:()=>Ae,dsv:()=>ms,dsvFormat:()=>po,easeBack:()=>as,easeBackIn:()=>rs,easeBackInOut:()=>as,easeBackOut:()=>is,easeBounce:()=>ts,easeBounceIn:()=>Jo,easeBounceInOut:()=>es,easeBounceOut:()=>ts,easeCircle:()=>Qo,easeCircleIn:()=>Xo,easeCircleInOut:()=>Qo,easeCircleOut:()=>Zo,easeCubic:()=>Gr,easeCubicIn:()=>Wr,easeCubicInOut:()=>Gr,easeCubicOut:()=>Vr,easeElastic:()=>cs,easeElasticIn:()=>ss,easeElasticInOut:()=>us,easeElasticOut:()=>cs,easeExp:()=>Go,easeExpIn:()=>Wo,easeExpInOut:()=>Go,easeExpOut:()=>Vo,easeLinear:()=>Bo,easePoly:()=>jo,easePolyIn:()=>Fo,easePolyInOut:()=>jo,easePolyOut:()=>Po,easeQuad:()=>Ro,easeQuadIn:()=>Lo,easeQuadInOut:()=>Ro,easeQuadOut:()=>Io,easeSin:()=>Ho,easeSinIn:()=>Uo,easeSinInOut:()=>Ho,easeSinOut:()=>qo,entries:()=>da,event:()=>le,extent:()=>m,forceCenter:()=>Ss,forceCollide:()=>Ys,forceLink:()=>qs,forceManyBody:()=>Gs,forceRadial:()=>Xs,forceSimulation:()=>Vs,forceX:()=>Zs,forceY:()=>Qs,format:()=>cc,formatDefaultLocale:()=>dc,formatLocale:()=>fc,formatPrefix:()=>uc,formatSpecifier:()=>nc,geoAlbers:()=>If,geoAlbersUsa:()=>Rf,geoArea:()=>uu,geoAzimuthalEqualArea:()=>Yf,geoAzimuthalEqualAreaRaw:()=>jf,geoAzimuthalEquidistant:()=>Uf,geoAzimuthalEquidistantRaw:()=>zf,geoBounds:()=>el,geoCentroid:()=>dl,geoCircle:()=>Tl,geoClipAntimeridian:()=>Rl,geoClipCircle:()=>Fl,geoClipExtent:()=>zl,geoClipRectangle:()=>Yl,geoConicConformal:()=>Gf,geoConicConformalRaw:()=>Vf,geoConicEqualArea:()=>Lf,geoConicEqualAreaRaw:()=>Bf,geoConicEquidistant:()=>Kf,geoConicEquidistantRaw:()=>Qf,geoContains:()=>ch,geoDistance:()=>Jl,geoEqualEarth:()=>ad,geoEqualEarthRaw:()=>id,geoEquirectangular:()=>Zf,geoEquirectangularRaw:()=>Xf,geoGnomonic:()=>sd,geoGnomonicRaw:()=>od,geoGraticule:()=>hh,geoGraticule10:()=>fh,geoIdentity:()=>cd,geoInterpolate:()=>dh,geoLength:()=>Zl,geoMercator:()=>Hf,geoMercatorRaw:()=>qf,geoNaturalEarth1:()=>ld,geoNaturalEarth1Raw:()=>ud,geoOrthographic:()=>fd,geoOrthographicRaw:()=>hd,geoPath:()=>gf,geoProjection:()=>Nf,geoProjectionMutator:()=>Df,geoRotation:()=>xl,geoStereographic:()=>pd,geoStereographicRaw:()=>dd,geoStream:()=>Zc,geoTransform:()=>mf,geoTransverseMercator:()=>gd,geoTransverseMercatorRaw:()=>yd,gray:()=>va,hcl:()=>Sa,hierarchy:()=>wd,histogram:()=>D,hsl:()=>rn,html:()=>Es,image:()=>_s,interpolate:()=>An,interpolateArray:()=>_n,interpolateBasis:()=>cn,interpolateBasisClosed:()=>un,interpolateBlues:()=>r_,interpolateBrBG:()=>yb,interpolateBuGn:()=>Bb,interpolateBuPu:()=>Ib,interpolateCividis:()=>p_,interpolateCool:()=>m_,interpolateCubehelix:()=>Lp,interpolateCubehelixDefault:()=>y_,interpolateCubehelixLong:()=>Ip,interpolateDate:()=>wn,interpolateDiscrete:()=>_p,interpolateGnBu:()=>Fb,interpolateGreens:()=>a_,interpolateGreys:()=>s_,interpolateHcl:()=>Dp,interpolateHclLong:()=>Op,interpolateHsl:()=>Sp,interpolateHslLong:()=>Ap,interpolateHue:()=>xp,interpolateInferno:()=>A_,interpolateLab:()=>Mp,interpolateMagma:()=>S_,interpolateNumber:()=>kn,interpolateNumberArray:()=>vn,interpolateObject:()=>Tn,interpolateOrRd:()=>jb,interpolateOranges:()=>d_,interpolatePRGn:()=>mb,interpolatePiYG:()=>bb,interpolatePlasma:()=>M_,interpolatePuBu:()=>qb,interpolatePuBuGn:()=>zb,interpolatePuOr:()=>xb,interpolatePuRd:()=>$b,interpolatePurples:()=>u_,interpolateRainbow:()=>b_,interpolateRdBu:()=>kb,interpolateRdGy:()=>Eb,interpolateRdPu:()=>Vb,interpolateRdYlBu:()=>Sb,interpolateRdYlGn:()=>Mb,interpolateReds:()=>h_,interpolateRgb:()=>pn,interpolateRgbBasis:()=>gn,interpolateRgbBasisClosed:()=>mn,interpolateRound:()=>wp,interpolateSinebow:()=>k_,interpolateSpectral:()=>Db,interpolateString:()=>Sn,interpolateTransformCss:()=>dr,interpolateTransformSvg:()=>pr,interpolateTurbo:()=>T_,interpolateViridis:()=>C_,interpolateWarm:()=>g_,interpolateYlGn:()=>Qb,interpolateYlGnBu:()=>Xb,interpolateYlOrBr:()=>Jb,interpolateYlOrRd:()=>e_,interpolateZoom:()=>Ep,interrupt:()=>ir,interval:()=>ek,isoFormat:()=>Jw,isoParse:()=>tk,json:()=>ws,keys:()=>ha,lab:()=>ba,lch:()=>Ca,line:()=>cx,lineRadial:()=>mx,linkHorizontal:()=>Sx,linkRadial:()=>Mx,linkVertical:()=>Ax,local:()=>O_,map:()=>ea,matcher:()=>mt,max:()=>I,mean:()=>R,median:()=>F,merge:()=>P,min:()=>j,mouse:()=>On,namespace:()=>Et,namespaces:()=>Tt,nest:()=>na,now:()=>qn,pack:()=>Vd,packEnclose:()=>Ad,packSiblings:()=>zd,pairs:()=>l,partition:()=>Jd,path:()=>$i,permute:()=>Y,pie:()=>fx,piecewise:()=>Rp,pointRadial:()=>bx,polygonArea:()=>Pp,polygonCentroid:()=>jp,polygonContains:()=>Hp,polygonHull:()=>qp,polygonLength:()=>$p,precisionFixed:()=>pc,precisionPrefix:()=>yc,precisionRound:()=>gc,quadtree:()=>Ls,quantile:()=>O,quantize:()=>Fp,radialArea:()=>vx,radialLine:()=>mx,randomBates:()=>Qp,randomExponential:()=>Kp,randomIrwinHall:()=>Zp,randomLogNormal:()=>Xp,randomNormal:()=>Gp,randomUniform:()=>Vp,range:()=>k,rgb:()=>Ze,ribbon:()=>Qi,scaleBand:()=>oy,scaleDiverging:()=>Qv,scaleDivergingLog:()=>Kv,scaleDivergingPow:()=>tb,scaleDivergingSqrt:()=>eb,scaleDivergingSymlog:()=>Jv,scaleIdentity:()=>wy,scaleImplicit:()=>iy,scaleLinear:()=>xy,scaleLog:()=>Dy,scaleOrdinal:()=>ay,scalePoint:()=>cy,scalePow:()=>Yy,scaleQuantile:()=>Uy,scaleQuantize:()=>qy,scaleSequential:()=>Hv,scaleSequentialLog:()=>$v,scaleSequentialPow:()=>Vv,scaleSequentialQuantile:()=>Xv,scaleSequentialSqrt:()=>Gv,scaleSequentialSymlog:()=>Wv,scaleSqrt:()=>zy,scaleSymlog:()=>Iy,scaleThreshold:()=>Hy,scaleTime:()=>Dv,scaleUtc:()=>zv,scan:()=>z,schemeAccent:()=>ib,schemeBlues:()=>n_,schemeBrBG:()=>pb,schemeBuGn:()=>Ob,schemeBuPu:()=>Lb,schemeCategory10:()=>rb,schemeDark2:()=>ab,schemeGnBu:()=>Rb,schemeGreens:()=>i_,schemeGreys:()=>o_,schemeOrRd:()=>Pb,schemeOranges:()=>f_,schemePRGn:()=>gb,schemePaired:()=>ob,schemePastel1:()=>sb,schemePastel2:()=>cb,schemePiYG:()=>vb,schemePuBu:()=>Ub,schemePuBuGn:()=>Yb,schemePuOr:()=>_b,schemePuRd:()=>Hb,schemePurples:()=>c_,schemeRdBu:()=>wb,schemeRdGy:()=>Tb,schemeRdPu:()=>Wb,schemeRdYlBu:()=>Cb,schemeRdYlGn:()=>Ab,schemeReds:()=>l_,schemeSet1:()=>ub,schemeSet2:()=>lb,schemeSet3:()=>hb,schemeSpectral:()=>Nb,schemeTableau10:()=>fb,schemeYlGn:()=>Zb,schemeYlGnBu:()=>Gb,schemeYlOrBr:()=>Kb,schemeYlOrRd:()=>t_,select:()=>Te,selectAll:()=>L_,selection:()=>ke,selector:()=>pt,selectorAll:()=>gt,set:()=>la,shuffle:()=>U,stack:()=>Yw,stackOffsetDiverging:()=>Uw,stackOffsetExpand:()=>zw,stackOffsetNone:()=>Fw,stackOffsetSilhouette:()=>qw,stackOffsetWiggle:()=>Hw,stackOrderAppearance:()=>$w,stackOrderAscending:()=>Vw,stackOrderDescending:()=>Xw,stackOrderInsideOut:()=>Zw,stackOrderNone:()=>Pw,stackOrderReverse:()=>Qw,stratify:()=>ip,style:()=>Rt,sum:()=>q,svg:()=>Cs,symbol:()=>Gx,symbolCircle:()=>Nx,symbolCross:()=>Dx,symbolDiamond:()=>Lx,symbolSquare:()=>jx,symbolStar:()=>Px,symbolTriangle:()=>zx,symbolWye:()=>Wx,symbols:()=>Vx,text:()=>ys,thresholdFreedmanDiaconis:()=>B,thresholdScott:()=>L,thresholdSturges:()=>N,tickFormat:()=>by,tickIncrement:()=>A,tickStep:()=>M,ticks:()=>S,timeDay:()=>bg,timeDays:()=>_g,timeFormat:()=>am,timeFormatDefaultLocale:()=>Cv,timeFormatLocale:()=>rm,timeFriday:()=>ug,timeFridays:()=>gg,timeHour:()=>wg,timeHours:()=>kg,timeInterval:()=>Vy,timeMillisecond:()=>Dg,timeMilliseconds:()=>Og,timeMinute:()=>Eg,timeMinutes:()=>Cg,timeMonday:()=>ag,timeMondays:()=>fg,timeMonth:()=>Ky,timeMonths:()=>Jy,timeParse:()=>om,timeSaturday:()=>lg,timeSaturdays:()=>mg,timeSecond:()=>Ag,timeSeconds:()=>Mg,timeSunday:()=>ig,timeSundays:()=>hg,timeThursday:()=>cg,timeThursdays:()=>yg,timeTuesday:()=>og,timeTuesdays:()=>dg,timeWednesday:()=>sg,timeWednesdays:()=>pg,timeWeek:()=>ig,timeWeeks:()=>hg,timeYear:()=>Xy,timeYears:()=>Zy,timeout:()=>Qn,timer:()=>Wn,timerFlush:()=>Vn,touch:()=>Dn,touches:()=>I_,transition:()=>qr,transpose:()=>H,tree:()=>hp,treemap:()=>gp,treemapBinary:()=>mp,treemapDice:()=>Kd,treemapResquarify:()=>bp,treemapSlice:()=>fp,treemapSliceDice:()=>vp,treemapSquarify:()=>yp,tsv:()=>bs,tsvFormat:()=>Co,tsvFormatBody:()=>So,tsvFormatRow:()=>Mo,tsvFormatRows:()=>Ao,tsvFormatValue:()=>No,tsvParse:()=>To,tsvParseRows:()=>Eo,utcDay:()=>Xg,utcDays:()=>Zg,utcFormat:()=>sm,utcFriday:()=>jg,utcFridays:()=>Wg,utcHour:()=>Rv,utcHours:()=>Fv,utcMillisecond:()=>Dg,utcMilliseconds:()=>Og,utcMinute:()=>jv,utcMinutes:()=>Yv,utcMonday:()=>Ig,utcMondays:()=>Ug,utcMonth:()=>Bv,utcMonths:()=>Lv,utcParse:()=>cm,utcSaturday:()=>Yg,utcSaturdays:()=>Vg,utcSecond:()=>Ag,utcSeconds:()=>Mg,utcSunday:()=>Lg,utcSundays:()=>zg,utcThursday:()=>Pg,utcThursdays:()=>$g,utcTuesday:()=>Rg,utcTuesdays:()=>qg,utcWednesday:()=>Fg,utcWednesdays:()=>Hg,utcWeek:()=>Lg,utcWeeks:()=>zg,utcYear:()=>Kg,utcYears:()=>Jg,values:()=>fa,variance:()=>y,version:()=>r,voronoi:()=>zk,window:()=>Ot,xml:()=>Ts,zip:()=>W,zoom:()=>eT,zoomIdentity:()=>$k,zoomTransform:()=>Wk});var r="5.16.0";function i(t,e){return te?1:t>=e?0:NaN}function a(t){var e;return 1===t.length&&(e=t,t=function(t,n){return i(e(t),n)}),{left:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)<0?r=a+1:i=a}return r},right:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)>0?i=a:r=a+1}return r}}}var o=a(i),s=o.right,c=o.left;const u=s;function l(t,e){null==e&&(e=h);for(var n=0,r=t.length-1,i=t[0],a=new Array(r<0?0:r);nt?1:e>=t?0:NaN}function p(t){return null===t?NaN:+t}function y(t,e){var n,r,i=t.length,a=0,o=-1,s=0,c=0;if(null==e)for(;++o1)return c/(a-1)}function g(t,e){var n=y(t,e);return n?Math.sqrt(n):n}function m(t,e){var n,r,i,a=t.length,o=-1;if(null==e){for(;++o=n)for(r=i=n;++on&&(r=n),i=n)for(r=i=n;++on&&(r=n),i0)return[t];if((r=e0)for(t=Math.ceil(t/o),e=Math.floor(e/o),a=new Array(i=Math.ceil(e-t+1));++s=0?(a>=T?10:a>=E?5:a>=C?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(a>=T?10:a>=E?5:a>=C?2:1)}function M(t,e,n){var r=Math.abs(e-t)/Math.max(0,n),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),a=r/i;return a>=T?i*=10:a>=E?i*=5:a>=C&&(i*=2),eh;)f.pop(),--d;var p,y=new Array(d+1);for(i=0;i<=d;++i)(p=y[i]=[]).x0=i>0?f[i-1]:l,p.x1=i=1)return+n(t[r-1],r-1,t);var r,i=(r-1)*e,a=Math.floor(i),o=+n(t[a],a,t);return o+(+n(t[a+1],a+1,t)-o)*(i-a)}}function B(t,e,n){return t=_.call(t,p).sort(i),Math.ceil((n-e)/(2*(O(t,.75)-O(t,.25))*Math.pow(t.length,-1/3)))}function L(t,e,n){return Math.ceil((n-e)/(3.5*g(t)*Math.pow(t.length,-1/3)))}function I(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++ar&&(r=n)}else for(;++a=n)for(r=n;++ar&&(r=n);return r}function R(t,e){var n,r=t.length,i=r,a=-1,o=0;if(null==e)for(;++a=0;)for(e=(r=t[i]).length;--e>=0;)n[--o]=r[e];return n}function j(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++an&&(r=n)}else for(;++a=n)for(r=n;++an&&(r=n);return r}function Y(t,e){for(var n=e.length,r=new Array(n);n--;)r[n]=t[e[n]];return r}function z(t,e){if(n=t.length){var n,r,a=0,o=0,s=t[o];for(null==e&&(e=i);++a=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function lt(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;ae?1:t>=e?0:NaN}bt.prototype={constructor:bt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var kt="http://www.w3.org/1999/xhtml";const Tt={svg:"http://www.w3.org/2000/svg",xhtml:kt,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Et(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Tt.hasOwnProperty(e)?{space:Tt[e],local:t}:t}function Ct(t){return function(){this.removeAttribute(t)}}function St(t){return function(){this.removeAttributeNS(t.space,t.local)}}function At(t,e){return function(){this.setAttribute(t,e)}}function Mt(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function Nt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function Dt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Ot(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Bt(t){return function(){this.style.removeProperty(t)}}function Lt(t,e,n){return function(){this.style.setProperty(t,e,n)}}function It(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Rt(t,e){return t.style.getPropertyValue(e)||Ot(t).getComputedStyle(t,null).getPropertyValue(e)}function Ft(t){return function(){delete this[t]}}function Pt(t,e){return function(){this[t]=e}}function jt(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function Yt(t){return t.trim().split(/^|\s+/)}function zt(t){return t.classList||new Ut(t)}function Ut(t){this._node=t,this._names=Yt(t.getAttribute("class")||"")}function qt(t,e){for(var n=zt(t),r=-1,i=e.length;++r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var ue={},le=null;function he(t,e,n){return t=fe(t,e,n),function(e){var n=e.relatedTarget;n&&(n===this||8&n.compareDocumentPosition(this))||t.call(this,e)}}function fe(t,e,n){return function(r){var i=le;le=r;try{t.call(this,this.__data__,e,n)}finally{le=i}}}function de(t){return t.trim().split(/^|\s+/).map((function(t){var e="",n=t.indexOf(".");return n>=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function pe(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=x&&(x=_+1);!(b=m[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=wt);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?Bt:"function"==typeof e?It:Lt)(t,e,null==n?"":n)):Rt(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Ft:"function"==typeof e?jt:Pt)(t,e)):this.node()[t]},classed:function(t,e){var n=Yt(t+"");if(arguments.length<2){for(var r=zt(this.node()),i=-1,a=n.length;++i>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Ge(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Ge(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Fe.exec(t))?new Qe(e[1],e[2],e[3],1):(e=Pe.exec(t))?new Qe(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=je.exec(t))?Ge(e[1],e[2],e[3],e[4]):(e=Ye.exec(t))?Ge(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=ze.exec(t))?en(e[1],e[2]/100,e[3]/100,1):(e=Ue.exec(t))?en(e[1],e[2]/100,e[3]/100,e[4]):qe.hasOwnProperty(t)?Ve(qe[t]):"transparent"===t?new Qe(NaN,NaN,NaN,0):null}function Ve(t){return new Qe(t>>16&255,t>>8&255,255&t,1)}function Ge(t,e,n,r){return r<=0&&(t=e=n=NaN),new Qe(t,e,n,r)}function Xe(t){return t instanceof De||(t=We(t)),t?new Qe((t=t.rgb()).r,t.g,t.b,t.opacity):new Qe}function Ze(t,e,n,r){return 1===arguments.length?Xe(t):new Qe(t,e,n,null==r?1:r)}function Qe(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Ke(){return"#"+tn(this.r)+tn(this.g)+tn(this.b)}function Je(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function tn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function en(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new an(t,e,n,r)}function nn(t){if(t instanceof an)return new an(t.h,t.s,t.l,t.opacity);if(t instanceof De||(t=We(t)),!t)return new an;if(t instanceof an)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new an(o,s,c,t.opacity)}function rn(t,e,n,r){return 1===arguments.length?nn(t):new an(t,e,n,null==r?1:r)}function an(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function on(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function sn(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}function cn(t){var e=t.length-1;return function(n){var r=n<=0?n=0:n>=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=r180||n<-180?n-360*Math.round(n/360):n):ln(isNaN(t)?e:t)}function dn(t,e){var n=e-t;return n?hn(t,n):ln(isNaN(t)?e:t)}Me(De,We,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:He,formatHex:He,formatHsl:function(){return nn(this).formatHsl()},formatRgb:$e,toString:$e}),Me(Qe,Ze,Ne(De,{brighter:function(t){return t=null==t?Oe:Math.pow(Oe,t),new Qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ke,formatHex:Ke,formatRgb:Je,toString:Je})),Me(an,rn,Ne(De,{brighter:function(t){return t=null==t?Oe:Math.pow(Oe,t),new an(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new an(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new Qe(on(t>=240?t-240:t+120,i,r),on(t,i,r),on(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const pn=function t(e){var n=function(t){return 1==(t=+t)?dn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):ln(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=Ze(t)).r,(e=Ze(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=dn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function yn(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;na&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:kn(n,r)})),a=Cn.lastIndex;return a=0&&e._call.call(null,t),e=e._next;--In}function Gn(){jn=(Pn=zn.now())+Yn,In=Rn=0;try{Vn()}finally{In=0,function(){for(var t,e,n=Bn,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:Bn=e);Ln=t,Zn(r)}(),jn=0}}function Xn(){var t=zn.now(),e=t-Pn;e>1e3&&(Yn-=e,Pn=t)}function Zn(t){In||(Rn&&(Rn=clearTimeout(Rn)),t-jn>24?(t<1/0&&(Rn=setTimeout(Gn,t-zn.now()-Yn)),Fn&&(Fn=clearInterval(Fn))):(Fn||(Pn=zn.now(),Fn=setInterval(Xn,1e3)),In=1,Un(Gn)))}function Qn(t,e,n){var r=new $n;return e=null==e?0:+e,r.restart((function(n){r.stop(),t(n+e)}),e,n),r}$n.prototype=Wn.prototype={constructor:$n,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?qn():+n)+(null==e?0:+e),this._next||Ln===this||(Ln?Ln._next=this:Bn=this,Ln=this),this._call=t,this._time=n,Zn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Zn())}};var Kn=ft("start","end","cancel","interrupt"),Jn=[];function tr(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return Qn(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function nr(t,e){var n=rr(t,e);if(n.state>3)throw new Error("too late; already running");return n}function rr(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function ir(t,e){var n,r,i,a=t.__transition,o=!0;if(a){for(i in e=null==e?null:e+"",a)(n=a[i]).name===e?(r=n.state>2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}var ar,or,sr,cr,ur=180/Math.PI,lr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function hr(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:kn(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:kn(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:kn(t,n)},{i:s-2,x:kn(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?er:nr;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var Ir=ke.prototype.constructor;function Rr(t){return function(){this.style.removeProperty(t)}}function Fr(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function Pr(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Fr(t,a,n)),r}return a._value=e,a}function jr(t){return function(e){this.textContent=t.call(this,e)}}function Yr(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&jr(r)),e}return r._value=t,r}var zr=0;function Ur(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function qr(t){return ke().transition(t)}function Hr(){return++zr}var $r=ke.prototype;function Wr(t){return t*t*t}function Vr(t){return--t*t*t+1}function Gr(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Ur.prototype=qr.prototype={constructor:Ur,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=pt(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o1&&n.name===e)return new Ur([[t]],Qr,e,+r);return null}function Jr(t){return function(){return t}}function ti(t,e,n){this.target=t,this.type=e,this.selection=n}function ei(){le.stopImmediatePropagation()}function ni(){le.preventDefault(),le.stopImmediatePropagation()}var ri={name:"drag"},ii={name:"space"},ai={name:"handle"},oi={name:"center"};function si(t){return[+t[0],+t[1]]}function ci(t){return[si(t[0]),si(t[1])]}function ui(t){return function(e){return Dn(e,le.touches,t)}}var li={name:"x",handles:["w","e"].map(vi),input:function(t,e){return null==t?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},hi={name:"y",handles:["n","s"].map(vi),input:function(t,e){return null==t?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},fi={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(vi),input:function(t){return null==t?null:ci(t)},output:function(t){return t}},di={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},pi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},yi={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},gi={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},mi={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function vi(t){return{type:t}}function bi(){return!le.ctrlKey&&!le.button}function _i(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function xi(){return navigator.maxTouchPoints||"ontouchstart"in this}function wi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function ki(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Ti(t){var e=t.__brush;return e?e.dim.output(e.selection):null}function Ei(){return Ai(li)}function Ci(){return Ai(hi)}function Si(){return Ai(fi)}function Ai(t){var e,n=_i,r=bi,i=xi,a=!0,o=ft("start","brush","end"),s=6;function c(e){var n=e.property("__brush",y).selectAll(".overlay").data([vi("overlay")]);n.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",di.overlay).merge(n).each((function(){var t=wi(this).extent;Te(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),e.selectAll(".selection").data([vi("selection")]).enter().append("rect").attr("class","selection").attr("cursor",di.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=e.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return di[t.type]})),e.each(u).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",f).filter(i).on("touchstart.brush",f).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function u(){var t=Te(this),e=wi(this).selection;e?(t.selectAll(".selection").style("display",null).attr("x",e[0][0]).attr("y",e[0][1]).attr("width",e[1][0]-e[0][0]).attr("height",e[1][1]-e[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?e[1][0]-s/2:e[0][0]-s/2})).attr("y",(function(t){return"s"===t.type[0]?e[1][1]-s/2:e[0][1]-s/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?e[1][0]-e[0][0]+s:s})).attr("height",(function(t){return"e"===t.type||"w"===t.type?e[1][1]-e[0][1]+s:s}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,e,n){var r=t.__brush.emitter;return!r||n&&r.clean?new h(t,e,n):r}function h(t,e,n){this.that=t,this.args=e,this.state=t.__brush,this.active=0,this.clean=n}function f(){if((!e||le.touches)&&r.apply(this,arguments)){var n,i,o,s,c,h,f,d,p,y,g,m=this,v=le.target.__data__.type,b="selection"===(a&&le.metaKey?v="overlay":v)?ri:a&&le.altKey?oi:ai,_=t===hi?null:gi[v],x=t===li?null:mi[v],w=wi(m),k=w.extent,T=w.selection,E=k[0][0],C=k[0][1],S=k[1][0],A=k[1][1],M=0,N=0,D=_&&x&&a&&le.shiftKey,O=le.touches?ui(le.changedTouches[0].identifier):On,B=O(m),L=B,I=l(m,arguments,!0).beforestart();"overlay"===v?(T&&(p=!0),w.selection=T=[[n=t===hi?E:B[0],o=t===li?C:B[1]],[c=t===hi?S:n,f=t===li?A:o]]):(n=T[0][0],o=T[0][1],c=T[1][0],f=T[1][1]),i=n,s=o,h=c,d=f;var R=Te(m).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",di[v]);if(le.touches)I.moved=j,I.ended=z;else{var P=Te(le.view).on("mousemove.brush",j,!0).on("mouseup.brush",z,!0);a&&P.on("keydown.brush",U,!0).on("keyup.brush",q,!0),Se(le.view)}ei(),ir(m),u.call(m),I.start()}function j(){var t=O(m);!D||y||g||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?g=!0:y=!0),L=t,p=!0,ni(),Y()}function Y(){var t;switch(M=L[0]-B[0],N=L[1]-B[1],b){case ii:case ri:_&&(M=Math.max(E-n,Math.min(S-c,M)),i=n+M,h=c+M),x&&(N=Math.max(C-o,Math.min(A-f,N)),s=o+N,d=f+N);break;case ai:_<0?(M=Math.max(E-n,Math.min(S-n,M)),i=n+M,h=c):_>0&&(M=Math.max(E-c,Math.min(S-c,M)),i=n,h=c+M),x<0?(N=Math.max(C-o,Math.min(A-o,N)),s=o+N,d=f):x>0&&(N=Math.max(C-f,Math.min(A-f,N)),s=o,d=f+N);break;case oi:_&&(i=Math.max(E,Math.min(S,n-M*_)),h=Math.max(E,Math.min(S,c+M*_))),x&&(s=Math.max(C,Math.min(A,o-N*x)),d=Math.max(C,Math.min(A,f+N*x)))}h0&&(n=i-M),x<0?f=d-N:x>0&&(o=s-N),b=ii,F.attr("cursor",di.selection),Y());break;default:return}ni()}function q(){switch(le.keyCode){case 16:D&&(y=g=D=!1,Y());break;case 18:b===oi&&(_<0?c=h:_>0&&(n=i),x<0?f=d:x>0&&(o=s),b=ai,Y());break;case 32:b===ii&&(le.altKey?(_&&(c=h-M*_,n=i+M*_),x&&(f=d-N*x,o=s+N*x),b=oi):(_<0?c=h:_>0&&(n=i),x<0?f=d:x>0&&(o=s),b=ai),F.attr("cursor",di[v]),Y());break;default:return}ni()}}function d(){l(this,arguments).moved()}function p(){l(this,arguments).ended()}function y(){var e=this.__brush||{selection:null};return e.extent=ci(n.apply(this,arguments)),e.dim=t,e}return c.move=function(e,n){e.selection?e.on("start.brush",(function(){l(this,arguments).beforestart().start()})).on("interrupt.brush end.brush",(function(){l(this,arguments).end()})).tween("brush",(function(){var e=this,r=e.__brush,i=l(e,arguments),a=r.selection,o=t.input("function"==typeof n?n.apply(this,arguments):n,r.extent),s=An(a,o);function c(t){r.selection=1===t&&null===o?null:s(t),u.call(e),i.brush()}return null!==a&&null!==o?c:c(1)})):e.each((function(){var e=this,r=arguments,i=e.__brush,a=t.input("function"==typeof n?n.apply(e,r):n,i.extent),o=l(e,r).beforestart();ir(e),i.selection=null===a?null:a,u.call(e),o.start().brush().end()}))},c.clear=function(t){c.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(e){ge(new ti(c,e,t.output(this.state.selection)),o.apply,o,[e,this.that,this.args])}},c.extent=function(t){return arguments.length?(n="function"==typeof t?t:Jr(ci(t)),c):n},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:Jr(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:Jr(!!t),c):i},c.handleSize=function(t){return arguments.length?(s=+t,c):s},c.keyModifiers=function(t){return arguments.length?(a=!!t,c):a},c.on=function(){var t=o.on.apply(o,arguments);return t===o?c:t},c}var Mi=Math.cos,Ni=Math.sin,Di=Math.PI,Oi=Di/2,Bi=2*Di,Li=Math.max;function Ii(t){return function(e,n){return t(e.source.value+e.target.value,n.source.value+n.target.value)}}function Ri(){var t=0,e=null,n=null,r=null;function i(i){var a,o,s,c,u,l,h=i.length,f=[],d=k(h),p=[],y=[],g=y.groups=new Array(h),m=new Array(h*h);for(a=0,u=-1;++uzi)if(Math.abs(l*s-c*u)>zi&&i){var f=n-a,d=r-o,p=s*s+c*c,y=f*f+d*d,g=Math.sqrt(p),m=Math.sqrt(h),v=i*Math.tan((ji-Math.acos((p+h-y)/(2*g*m)))/2),b=v/m,_=v/g;Math.abs(b-1)>zi&&(this._+="L"+(t+b*u)+","+(e+b*l)),this._+="A"+i+","+i+",0,0,"+ +(l*f>u*d)+","+(this._x1=t+_*s)+","+(this._y1=e+_*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e)},arc:function(t,e,n,r,i,a){t=+t,e=+e,a=!!a;var o=(n=+n)*Math.cos(r),s=n*Math.sin(r),c=t+o,u=e+s,l=1^a,h=a?r-i:i-r;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+u:(Math.abs(this._x1-c)>zi||Math.abs(this._y1-u)>zi)&&(this._+="L"+c+","+u),n&&(h<0&&(h=h%Yi+Yi),h>Ui?this._+="A"+n+","+n+",0,1,"+l+","+(t-o)+","+(e-s)+"A"+n+","+n+",0,1,"+l+","+(this._x1=c)+","+(this._y1=u):h>zi&&(this._+="A"+n+","+n+",0,"+ +(h>=ji)+","+l+","+(this._x1=t+n*Math.cos(i))+","+(this._y1=e+n*Math.sin(i))))},rect:function(t,e,n,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};const $i=Hi;function Wi(t){return t.source}function Vi(t){return t.target}function Gi(t){return t.radius}function Xi(t){return t.startAngle}function Zi(t){return t.endAngle}function Qi(){var t=Wi,e=Vi,n=Gi,r=Xi,i=Zi,a=null;function o(){var o,s=Fi.call(arguments),c=t.apply(this,s),u=e.apply(this,s),l=+n.apply(this,(s[0]=c,s)),h=r.apply(this,s)-Oi,f=i.apply(this,s)-Oi,d=l*Mi(h),p=l*Ni(h),y=+n.apply(this,(s[0]=u,s)),g=r.apply(this,s)-Oi,m=i.apply(this,s)-Oi;if(a||(a=o=$i()),a.moveTo(d,p),a.arc(0,0,l,h,f),h===g&&f===m||(a.quadraticCurveTo(0,0,y*Mi(g),y*Ni(g)),a.arc(0,0,y,g,m)),a.quadraticCurveTo(0,0,d,p),a.closePath(),o)return a=null,o+""||null}return o.radius=function(t){return arguments.length?(n="function"==typeof t?t:Pi(+t),o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Pi(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Pi(+t),o):i},o.source=function(e){return arguments.length?(t=e,o):t},o.target=function(t){return arguments.length?(e=t,o):e},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o}var Ki="$";function Ji(){}function ta(t,e){var n=new Ji;if(t instanceof Ji)t.each((function(t,e){n.set(e,t)}));else if(Array.isArray(t)){var r,i=-1,a=t.length;if(null==e)for(;++i=r.length)return null!=t&&n.sort(t),null!=e?e(n):n;for(var c,u,l,h=-1,f=n.length,d=r[i++],p=ea(),y=o();++hr.length)return n;var o,s=i[a-1];return null!=e&&a>=r.length?o=n.entries():(o=[],n.each((function(e,n){o.push({key:n,values:t(e,a)})}))),null!=s?o.sort((function(t,e){return s(t.key,e.key)})):o}(a(t,0,aa,oa),0)},key:function(t){return r.push(t),n},sortKeys:function(t){return i[r.length-1]=t,n},sortValues:function(e){return t=e,n},rollup:function(t){return e=t,n}}}function ra(){return{}}function ia(t,e,n){t[e]=n}function aa(){return ea()}function oa(t,e,n){t.set(e,n)}function sa(){}var ca=ea.prototype;function ua(t,e){var n=new sa;if(t instanceof sa)t.each((function(t){n.add(t)}));else if(t){var r=-1,i=t.length;if(null==e)for(;++r.008856451679035631?Math.pow(t,1/3):t/ga+4/29}function wa(t){return t>6/29?t*t*t:ga*(t-4/29)}function ka(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Ta(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Ea(t){if(t instanceof Aa)return new Aa(t.h,t.c,t.l,t.opacity);if(t instanceof _a||(t=ma(t)),0===t.a&&0===t.b)return new Aa(NaN,0r!=d>r&&n<(f-u)*(r-l)/(d-l)+u&&(i=-i)}return i}function $a(t,e,n){var r,i,a,o;return function(t,e,n){return(e[0]-t[0])*(n[1]-t[1])==(n[0]-t[0])*(e[1]-t[1])}(t,e,n)&&(i=t[r=+(t[0]===e[0])],a=n[r],o=e[r],i<=a&&a<=o||o<=a&&a<=i)}function Wa(){}var Va=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function Ga(){var t=1,e=1,n=N,r=s;function i(t){var e=n(t);if(Array.isArray(e))e=e.slice().sort(za);else{var r=m(t),i=r[0],o=r[1];e=M(i,o,e),e=k(Math.floor(i/e)*e,Math.floor(o/e)*e,e)}return e.map((function(e){return a(t,e)}))}function a(n,i){var a=[],s=[];return function(n,r,i){var a,s,c,u,l,h,f=new Array,d=new Array;for(a=s=-1,u=n[0]>=r,Va[u<<1].forEach(p);++a=r,Va[c|u<<1].forEach(p);for(Va[u<<0].forEach(p);++s=r,l=n[s*t]>=r,Va[u<<1|l<<2].forEach(p);++a=r,h=l,l=n[s*t+a+1]>=r,Va[c|u<<1|l<<2|h<<3].forEach(p);Va[u|l<<3].forEach(p)}for(a=-1,l=n[s*t]>=r,Va[l<<2].forEach(p);++a=r,Va[l<<2|h<<3].forEach(p);function p(t){var e,n,r=[t[0][0]+a,t[0][1]+s],c=[t[1][0]+a,t[1][1]+s],u=o(r),l=o(c);(e=d[u])?(n=f[l])?(delete d[e.end],delete f[n.start],e===n?(e.ring.push(c),i(e.ring)):f[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete d[e.end],e.ring.push(c),d[e.end=l]=e):(e=f[l])?(n=d[u])?(delete f[e.start],delete d[n.end],e===n?(e.ring.push(c),i(e.ring)):f[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete f[e.start],e.ring.unshift(r),f[e.start=u]=e):f[u]=d[l]={start:u,end:l,ring:[r,c]}}Va[l<<3].forEach(p)}(n,i,(function(t){r(t,n,i),function(t){for(var e=0,n=t.length,r=t[n-1][1]*t[0][0]-t[n-1][0]*t[0][1];++e0?a.push([t]):s.push(t)})),s.forEach((function(t){for(var e,n=0,r=a.length;n0&&o0&&s0&&a>0))throw new Error("invalid size");return t=r,e=a,i},i.thresholds=function(t){return arguments.length?(n="function"==typeof t?t:Array.isArray(t)?Ua(Ya.call(t)):Ua(t),i):n},i.smooth=function(t){return arguments.length?(r=t?s:Wa,i):r===s},i}function Xa(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[s-a+o*r]),e.data[s-n+o*r]=c/Math.min(s+1,r-1+a-s,a))}function Za(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[o+(s-a)*r]),e.data[o+(s-n)*r]=c/Math.min(s+1,i-1+a-s,a))}function Qa(t){return t[0]}function Ka(t){return t[1]}function Ja(){return 1}function to(){var t=Qa,e=Ka,n=Ja,r=960,i=500,a=20,o=2,s=3*a,c=r+2*s>>o,u=i+2*s>>o,l=Ua(20);function h(r){var i=new Float32Array(c*u),h=new Float32Array(c*u);r.forEach((function(r,a,l){var h=+t(r,a,l)+s>>o,f=+e(r,a,l)+s>>o,d=+n(r,a,l);h>=0&&h=0&&f>o),Za({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),Xa({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),Za({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),Xa({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),Za({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o);var d=l(i);if(!Array.isArray(d)){var p=I(i);d=M(0,p,d),(d=k(0,Math.floor(p/d)*d,d)).shift()}return Ga().thresholds(d).size([c,u])(i).map(f)}function f(t){return t.value*=Math.pow(2,-2*o),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(y)}function y(t){t[0]=t[0]*Math.pow(2,o)-s,t[1]=t[1]*Math.pow(2,o)-s}function g(){return c=r+2*(s=3*a)>>o,u=i+2*s>>o,h}return h.x=function(e){return arguments.length?(t="function"==typeof e?e:Ua(+e),h):t},h.y=function(t){return arguments.length?(e="function"==typeof t?t:Ua(+t),h):e},h.weight=function(t){return arguments.length?(n="function"==typeof t?t:Ua(+t),h):n},h.size=function(t){if(!arguments.length)return[r,i];var e=Math.ceil(t[0]),n=Math.ceil(t[1]);if(!(e>=0||e>=0))throw new Error("invalid size");return r=e,i=n,g()},h.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return o=Math.floor(Math.log(t)/Math.LN2),g()},h.thresholds=function(t){return arguments.length?(l="function"==typeof t?t:Array.isArray(t)?Ua(Ya.call(t)):Ua(t),h):l},h.bandwidth=function(t){if(!arguments.length)return Math.sqrt(a*(a+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return a=Math.round((Math.sqrt(4*t*t+1)-1)/2),g()},h}function eo(t){return function(){return t}}function no(t,e,n,r,i,a,o,s,c,u){this.target=t,this.type=e,this.subject=n,this.identifier=r,this.active=i,this.x=a,this.y=o,this.dx=s,this.dy=c,this._=u}function ro(){return!le.ctrlKey&&!le.button}function io(){return this.parentNode}function ao(t){return null==t?{x:le.x,y:le.y}:t}function oo(){return navigator.maxTouchPoints||"ontouchstart"in this}function so(){var t,e,n,r,i=ro,a=io,o=ao,s=oo,c={},u=ft("start","drag","end"),l=0,h=0;function f(t){t.on("mousedown.drag",d).filter(s).on("touchstart.drag",g).on("touchmove.drag",m).on("touchend.drag touchcancel.drag",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(){if(!r&&i.apply(this,arguments)){var o=b("mouse",a.apply(this,arguments),On,this,arguments);o&&(Te(le.view).on("mousemove.drag",p,!0).on("mouseup.drag",y,!0),Se(le.view),Ee(),n=!1,t=le.clientX,e=le.clientY,o("start"))}}function p(){if(Ce(),!n){var r=le.clientX-t,i=le.clientY-e;n=r*r+i*i>h}c.mouse("drag")}function y(){Te(le.view).on("mousemove.drag mouseup.drag",null),Ae(le.view,n),Ce(),c.mouse("end")}function g(){if(i.apply(this,arguments)){var t,e,n=le.changedTouches,r=a.apply(this,arguments),o=n.length;for(t=0;t=a?c=!0:10===(r=t.charCodeAt(o++))?u=!0:13===r&&(u=!0,10===t.charCodeAt(o)&&++o),t.slice(i+1,e-1).replace(/""/g,'"')}for(;o9999?"+"+fo(t,6):fo(t,4)}(t.getUTCFullYear())+"-"+fo(t.getUTCMonth()+1,2)+"-"+fo(t.getUTCDate(),2)+(i?"T"+fo(e,2)+":"+fo(n,2)+":"+fo(r,2)+"."+fo(i,3)+"Z":r?"T"+fo(e,2)+":"+fo(n,2)+":"+fo(r,2)+"Z":n||e?"T"+fo(e,2)+":"+fo(n,2)+"Z":"")}(t):e.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,e){var n,i,a=r(t,(function(t,r){if(n)return n(t,r-1);i=t,n=e?function(t,e){var n=lo(t);return function(r,i){return e(n(r),i,t)}}(t,e):lo(t)}));return a.columns=i||[],a},parseRows:r,format:function(e,n){return null==n&&(n=ho(e)),[n.map(o).join(t)].concat(i(e,n)).join("\n")},formatBody:function(t,e){return null==e&&(e=ho(t)),i(t,e).join("\n")},formatRows:function(t){return t.map(a).join("\n")},formatRow:a,formatValue:o}}var yo=po(","),go=yo.parse,mo=yo.parseRows,vo=yo.format,bo=yo.formatBody,_o=yo.formatRows,xo=yo.formatRow,wo=yo.formatValue,ko=po("\t"),To=ko.parse,Eo=ko.parseRows,Co=ko.format,So=ko.formatBody,Ao=ko.formatRows,Mo=ko.formatRow,No=ko.formatValue;function Do(t){for(var e in t){var n,r,i=t[e].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(n=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;Oo&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=n;else i=null;t[e]=i}return t}var Oo=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function Bo(t){return+t}function Lo(t){return t*t}function Io(t){return t*(2-t)}function Ro(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}var Fo=function t(e){function n(t){return Math.pow(t,e)}return e=+e,n.exponent=t,n}(3),Po=function t(e){function n(t){return 1-Math.pow(1-t,e)}return e=+e,n.exponent=t,n}(3),jo=function t(e){function n(t){return((t*=2)<=1?Math.pow(t,e):2-Math.pow(2-t,e))/2}return e=+e,n.exponent=t,n}(3),Yo=Math.PI,zo=Yo/2;function Uo(t){return 1==+t?1:1-Math.cos(t*zo)}function qo(t){return Math.sin(t*zo)}function Ho(t){return(1-Math.cos(Yo*t))/2}function $o(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function Wo(t){return $o(1-+t)}function Vo(t){return 1-$o(t)}function Go(t){return((t*=2)<=1?$o(1-t):2-$o(t-1))/2}function Xo(t){return 1-Math.sqrt(1-t*t)}function Zo(t){return Math.sqrt(1- --t*t)}function Qo(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Ko=7.5625;function Jo(t){return 1-ts(1-t)}function ts(t){return(t=+t)<.36363636363636365?Ko*t*t:t<.7272727272727273?Ko*(t-=.5454545454545454)*t+.75:t<.9090909090909091?Ko*(t-=.8181818181818182)*t+.9375:Ko*(t-=.9545454545454546)*t+.984375}function es(t){return((t*=2)<=1?1-ts(1-t):ts(t-1)+1)/2}var ns=1.70158,rs=function t(e){function n(t){return(t=+t)*t*(e*(t-1)+t)}return e=+e,n.overshoot=t,n}(ns),is=function t(e){function n(t){return--t*t*((t+1)*e+t)+1}return e=+e,n.overshoot=t,n}(ns),as=function t(e){function n(t){return((t*=2)<1?t*t*((e+1)*t-e):(t-=2)*t*((e+1)*t+e)+2)/2}return e=+e,n.overshoot=t,n}(ns),os=2*Math.PI,ss=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=os);function i(t){return e*$o(- --t)*Math.sin((r-t)/n)}return i.amplitude=function(e){return t(e,n*os)},i.period=function(n){return t(e,n)},i}(1,.3),cs=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=os);function i(t){return 1-e*$o(t=+t)*Math.sin((t+r)/n)}return i.amplitude=function(e){return t(e,n*os)},i.period=function(n){return t(e,n)},i}(1,.3),us=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=os);function i(t){return((t=2*t-1)<0?e*$o(-t)*Math.sin((r-t)/n):2-e*$o(t)*Math.sin((r+t)/n))/2}return i.amplitude=function(e){return t(e,n*os)},i.period=function(n){return t(e,n)},i}(1,.3);function ls(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function hs(t,e){return fetch(t,e).then(ls)}function fs(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function ds(t,e){return fetch(t,e).then(fs)}function ps(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function ys(t,e){return fetch(t,e).then(ps)}function gs(t){return function(e,n,r){return 2===arguments.length&&"function"==typeof n&&(r=n,n=void 0),ys(e,n).then((function(e){return t(e,r)}))}}function ms(t,e,n,r){3===arguments.length&&"function"==typeof n&&(r=n,n=void 0);var i=po(t);return ys(e,n).then((function(t){return i.parse(t,r)}))}var vs=gs(go),bs=gs(To);function _s(t,e){return new Promise((function(n,r){var i=new Image;for(var a in e)i[a]=e[a];i.onerror=r,i.onload=function(){n(i)},i.src=t}))}function xs(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function ws(t,e){return fetch(t,e).then(xs)}function ks(t){return function(e,n){return ys(e,n).then((function(e){return(new DOMParser).parseFromString(e,t)}))}}const Ts=ks("application/xml");var Es=ks("text/html"),Cs=ks("image/svg+xml");function Ss(t,e){var n;function r(){var r,i,a=n.length,o=0,s=0;for(r=0;r=(a=(y+m)/2))?y=a:m=a,(l=n>=(o=(g+v)/2))?g=o:v=o,i=d,!(d=d[h=l<<1|u]))return i[h]=p,t;if(s=+t._x.call(null,d.data),c=+t._y.call(null,d.data),e===s&&n===c)return p.next=d,i?i[h]=p:t._root=p,t;do{i=i?i[h]=new Array(4):t._root=new Array(4),(u=e>=(a=(y+m)/2))?y=a:m=a,(l=n>=(o=(g+v)/2))?g=o:v=o}while((h=l<<1|u)==(f=(c>=o)<<1|s>=a));return i[f]=d,i[h]=p,t}function Ds(t,e,n,r,i){this.node=t,this.x0=e,this.y0=n,this.x1=r,this.y1=i}function Os(t){return t[0]}function Bs(t){return t[1]}function Ls(t,e,n){var r=new Is(null==e?Os:e,null==n?Bs:n,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Is(t,e,n,r,i,a){this._x=t,this._y=e,this._x0=n,this._y0=r,this._x1=i,this._y1=a,this._root=void 0}function Rs(t){for(var e={data:t.data},n=e;t=t.next;)n=n.next={data:t.data};return e}var Fs=Ls.prototype=Is.prototype;function Ps(t){return t.x+t.vx}function js(t){return t.y+t.vy}function Ys(t){var e,n,r=1,i=1;function a(){for(var t,a,s,c,u,l,h,f=e.length,d=0;dc+d||iu+d||as.index){var p=c-o.x-o.vx,y=u-o.y-o.vy,g=p*p+y*y;gt.r&&(t.r=t[e].r)}function s(){if(e){var r,i,a=e.length;for(n=new Array(a),r=0;rl&&(l=r),ih&&(h=i));if(c>l||u>h)return this;for(this.cover(c,u).cover(l,h),n=0;nt||t>=i||r>e||e>=a;)switch(s=(ef||(a=c.y0)>d||(o=c.x1)=m)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-u],p[p.length-1-u]=c)}else{var v=t-+this._x.call(null,y.data),b=e-+this._y.call(null,y.data),_=v*v+b*b;if(_=(s=(p+g)/2))?p=s:g=s,(l=o>=(c=(y+m)/2))?y=c:m=c,e=d,!(d=d[h=l<<1|u]))return this;if(!d.length)break;(e[h+1&3]||e[h+2&3]||e[h+3&3])&&(n=e,f=h)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):e?(i?e[h]=i:delete e[h],(d=e[0]||e[1]||e[2]||e[3])&&d===(e[3]||e[2]||e[1]||e[0])&&!d.length&&(n?n[f]=d:this._root=d),this):(this._root=i,this)},Fs.removeAll=function(t){for(var e=0,n=t.length;e1?(null==n?s.remove(t):s.set(t,d(n)),e):s.get(t)},find:function(e,n,r){var i,a,o,s,c,u=0,l=t.length;for(null==r?r=1/0:r*=r,u=0;u1?(u.on(t,n),e):u.on(t)}}}function Gs(){var t,e,n,r,i=As(-30),a=1,o=1/0,s=.81;function c(r){var i,a=t.length,o=Ls(t,Hs,$s).visitAfter(l);for(n=r,i=0;i=o)){(t.data!==e||t.next)&&(0===l&&(d+=(l=Ms())*l),0===h&&(d+=(h=Ms())*h),d1?r[0]+r.slice(2):r,+t.slice(n+1)]}function Js(t){return(t=Ks(Math.abs(t)))?t[1]:NaN}var tc,ec=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function nc(t){if(!(e=ec.exec(t)))throw new Error("invalid format: "+t);var e;return new rc({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function rc(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function ic(t,e){var n=Ks(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}nc.prototype=rc.prototype,rc.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const ac={"%":function(t,e){return(100*t).toFixed(e)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:function(t,e){return t.toExponential(e)},f:function(t,e){return t.toFixed(e)},g:function(t,e){return t.toPrecision(e)},o:function(t){return Math.round(t).toString(8)},p:function(t,e){return ic(100*t,e)},r:ic,s:function(t,e){var n=Ks(t,e);if(!n)return t+"";var r=n[0],i=n[1],a=i-(tc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=r.length;return a===o?r:a>o?r+new Array(a-o+1).join("0"):a>0?r.slice(0,a)+"."+r.slice(a):"0."+new Array(1-a).join("0")+Ks(t,Math.max(0,e+a-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function oc(t){return t}var sc,cc,uc,lc=Array.prototype.map,hc=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function fc(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?oc:(e=lc.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,a=[],o=0,s=e[0],c=0;i>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),a.push(t.substring(i-=s,i+s)),!((c+=s+1)>r));)s=e[o=(o+1)%e.length];return a.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?oc:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(lc.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",u=void 0===t.minus?"-":t.minus+"",l=void 0===t.nan?"NaN":t.nan+"";function h(t){var e=(t=nc(t)).fill,n=t.align,h=t.sign,f=t.symbol,d=t.zero,p=t.width,y=t.comma,g=t.precision,m=t.trim,v=t.type;"n"===v?(y=!0,v="g"):ac[v]||(void 0===g&&(g=12),m=!0,v="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var b="$"===f?i:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",_="$"===f?a:/[%p]/.test(v)?c:"",x=ac[v],w=/[defgprs%]/.test(v);function k(t){var i,a,c,f=b,k=_;if("c"===v)k=x(t)+k,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?l:x(Math.abs(t),g),m&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),T&&0==+t&&"+"!==h&&(T=!1),f=(T?"("===h?h:u:"-"===h||"("===h?"":h)+f,k=("s"===v?hc[8+tc/3]:"")+k+(T&&"("===h?")":""),w)for(i=-1,a=t.length;++i(c=t.charCodeAt(i))||c>57){k=(46===c?o+t.slice(i+1):t.slice(i))+k,t=t.slice(0,i);break}}y&&!d&&(t=r(t,1/0));var E=f.length+t.length+k.length,C=E>1)+f+t+k+C.slice(E);break;default:t=C+f+t+k}return s(t)}return g=void 0===g?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),k.toString=function(){return t+""},k}return{format:h,formatPrefix:function(t,e){var n=h(((t=nc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Js(e)/3))),i=Math.pow(10,-r),a=hc[8+r/3];return function(t){return n(i*t)+a}}}}function dc(t){return sc=fc(t),cc=sc.format,uc=sc.formatPrefix,sc}function pc(t){return Math.max(0,-Js(Math.abs(t)))}function yc(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Js(e)/3)))-Js(Math.abs(t)))}function gc(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,Js(e)-Js(t))+1}function mc(){return new vc}function vc(){this.reset()}dc({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),vc.prototype={constructor:vc,reset:function(){this.s=this.t=0},add:function(t){_c(bc,t,this.t),_c(this,bc.s,this.s),this.s?this.t+=bc.t:this.s=bc.t},valueOf:function(){return this.s}};var bc=new vc;function _c(t,e,n){var r=t.s=e+n,i=r-e,a=r-i;t.t=e-a+(n-i)}var xc=1e-6,wc=1e-12,kc=Math.PI,Tc=kc/2,Ec=kc/4,Cc=2*kc,Sc=180/kc,Ac=kc/180,Mc=Math.abs,Nc=Math.atan,Dc=Math.atan2,Oc=Math.cos,Bc=Math.ceil,Lc=Math.exp,Ic=(Math.floor,Math.log),Rc=Math.pow,Fc=Math.sin,Pc=Math.sign||function(t){return t>0?1:t<0?-1:0},jc=Math.sqrt,Yc=Math.tan;function zc(t){return t>1?0:t<-1?kc:Math.acos(t)}function Uc(t){return t>1?Tc:t<-1?-Tc:Math.asin(t)}function qc(t){return(t=Fc(t/2))*t}function Hc(){}function $c(t,e){t&&Vc.hasOwnProperty(t.type)&&Vc[t.type](t,e)}var Wc={Feature:function(t,e){$c(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r=0?1:-1,i=r*n,a=Oc(e=(e*=Ac)/2+Ec),o=Fc(e),s=eu*o,c=tu*a+s*Oc(i),u=s*r*Fc(i);nu.add(Dc(u,c)),Jc=t,tu=a,eu=o}function uu(t){return ru.reset(),Zc(t,iu),2*ru}function lu(t){return[Dc(t[1],t[0]),Uc(t[2])]}function hu(t){var e=t[0],n=t[1],r=Oc(n);return[r*Oc(e),r*Fc(e),Fc(n)]}function fu(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function du(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function pu(t,e){t[0]+=e[0],t[1]+=e[1],t[2]+=e[2]}function yu(t,e){return[t[0]*e,t[1]*e,t[2]*e]}function gu(t){var e=jc(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=e,t[1]/=e,t[2]/=e}var mu,vu,bu,_u,xu,wu,ku,Tu,Eu,Cu,Su,Au,Mu,Nu,Du,Ou,Bu,Lu,Iu,Ru,Fu,Pu,ju,Yu,zu,Uu,qu=mc(),Hu={point:$u,lineStart:Vu,lineEnd:Gu,polygonStart:function(){Hu.point=Xu,Hu.lineStart=Zu,Hu.lineEnd=Qu,qu.reset(),iu.polygonStart()},polygonEnd:function(){iu.polygonEnd(),Hu.point=$u,Hu.lineStart=Vu,Hu.lineEnd=Gu,nu<0?(mu=-(bu=180),vu=-(_u=90)):qu>xc?_u=90:qu<-1e-6&&(vu=-90),Cu[0]=mu,Cu[1]=bu},sphere:function(){mu=-(bu=180),vu=-(_u=90)}};function $u(t,e){Eu.push(Cu=[mu=t,bu=t]),e_u&&(_u=e)}function Wu(t,e){var n=hu([t*Ac,e*Ac]);if(Tu){var r=du(Tu,n),i=du([r[1],-r[0],0],r);gu(i),i=lu(i);var a,o=t-xu,s=o>0?1:-1,c=i[0]*Sc*s,u=Mc(o)>180;u^(s*xu_u&&(_u=a):u^(s*xu<(c=(c+360)%360-180)&&c_u&&(_u=e)),u?tKu(mu,bu)&&(bu=t):Ku(t,bu)>Ku(mu,bu)&&(mu=t):bu>=mu?(tbu&&(bu=t)):t>xu?Ku(mu,t)>Ku(mu,bu)&&(bu=t):Ku(t,bu)>Ku(mu,bu)&&(mu=t)}else Eu.push(Cu=[mu=t,bu=t]);e_u&&(_u=e),Tu=n,xu=t}function Vu(){Hu.point=Wu}function Gu(){Cu[0]=mu,Cu[1]=bu,Hu.point=$u,Tu=null}function Xu(t,e){if(Tu){var n=t-xu;qu.add(Mc(n)>180?n+(n>0?360:-360):n)}else wu=t,ku=e;iu.point(t,e),Wu(t,e)}function Zu(){iu.lineStart()}function Qu(){Xu(wu,ku),iu.lineEnd(),Mc(qu)>xc&&(mu=-(bu=180)),Cu[0]=mu,Cu[1]=bu,Tu=null}function Ku(t,e){return(e-=t)<0?e+360:e}function Ju(t,e){return t[0]-e[0]}function tl(t,e){return t[0]<=t[1]?t[0]<=e&&e<=t[1]:eKu(r[0],r[1])&&(r[1]=i[1]),Ku(i[0],r[1])>Ku(r[0],r[1])&&(r[0]=i[0])):a.push(r=i);for(o=-1/0,e=0,r=a[n=a.length-1];e<=n;r=i,++e)i=a[e],(s=Ku(r[1],i[0]))>o&&(o=s,mu=i[0],bu=r[1])}return Eu=Cu=null,mu===1/0||vu===1/0?[[NaN,NaN],[NaN,NaN]]:[[mu,vu],[bu,_u]]}var nl={sphere:Hc,point:rl,lineStart:al,lineEnd:cl,polygonStart:function(){nl.lineStart=ul,nl.lineEnd=ll},polygonEnd:function(){nl.lineStart=al,nl.lineEnd=cl}};function rl(t,e){t*=Ac;var n=Oc(e*=Ac);il(n*Oc(t),n*Fc(t),Fc(e))}function il(t,e,n){++Su,Mu+=(t-Mu)/Su,Nu+=(e-Nu)/Su,Du+=(n-Du)/Su}function al(){nl.point=ol}function ol(t,e){t*=Ac;var n=Oc(e*=Ac);Yu=n*Oc(t),zu=n*Fc(t),Uu=Fc(e),nl.point=sl,il(Yu,zu,Uu)}function sl(t,e){t*=Ac;var n=Oc(e*=Ac),r=n*Oc(t),i=n*Fc(t),a=Fc(e),o=Dc(jc((o=zu*a-Uu*i)*o+(o=Uu*r-Yu*a)*o+(o=Yu*i-zu*r)*o),Yu*r+zu*i+Uu*a);Au+=o,Ou+=o*(Yu+(Yu=r)),Bu+=o*(zu+(zu=i)),Lu+=o*(Uu+(Uu=a)),il(Yu,zu,Uu)}function cl(){nl.point=rl}function ul(){nl.point=hl}function ll(){fl(Pu,ju),nl.point=rl}function hl(t,e){Pu=t,ju=e,t*=Ac,e*=Ac,nl.point=fl;var n=Oc(e);Yu=n*Oc(t),zu=n*Fc(t),Uu=Fc(e),il(Yu,zu,Uu)}function fl(t,e){t*=Ac;var n=Oc(e*=Ac),r=n*Oc(t),i=n*Fc(t),a=Fc(e),o=zu*a-Uu*i,s=Uu*r-Yu*a,c=Yu*i-zu*r,u=jc(o*o+s*s+c*c),l=Uc(u),h=u&&-l/u;Iu+=h*o,Ru+=h*s,Fu+=h*c,Au+=l,Ou+=l*(Yu+(Yu=r)),Bu+=l*(zu+(zu=i)),Lu+=l*(Uu+(Uu=a)),il(Yu,zu,Uu)}function dl(t){Su=Au=Mu=Nu=Du=Ou=Bu=Lu=Iu=Ru=Fu=0,Zc(t,nl);var e=Iu,n=Ru,r=Fu,i=e*e+n*n+r*r;return ikc?t+Math.round(-t/Cc)*Cc:t,e]}function ml(t,e,n){return(t%=Cc)?e||n?yl(bl(t),_l(e,n)):bl(t):e||n?_l(e,n):gl}function vl(t){return function(e,n){return[(e+=t)>kc?e-Cc:e<-kc?e+Cc:e,n]}}function bl(t){var e=vl(t);return e.invert=vl(-t),e}function _l(t,e){var n=Oc(t),r=Fc(t),i=Oc(e),a=Fc(e);function o(t,e){var o=Oc(e),s=Oc(t)*o,c=Fc(t)*o,u=Fc(e),l=u*n+s*r;return[Dc(c*i-l*a,s*n-u*r),Uc(l*i+c*a)]}return o.invert=function(t,e){var o=Oc(e),s=Oc(t)*o,c=Fc(t)*o,u=Fc(e),l=u*i-c*a;return[Dc(c*i+u*a,s*n+l*r),Uc(l*n-s*r)]},o}function xl(t){function e(e){return(e=t(e[0]*Ac,e[1]*Ac))[0]*=Sc,e[1]*=Sc,e}return t=ml(t[0]*Ac,t[1]*Ac,t.length>2?t[2]*Ac:0),e.invert=function(e){return(e=t.invert(e[0]*Ac,e[1]*Ac))[0]*=Sc,e[1]*=Sc,e},e}function wl(t,e,n,r,i,a){if(n){var o=Oc(e),s=Fc(e),c=r*n;null==i?(i=e+r*Cc,a=e-c/2):(i=kl(o,i),a=kl(o,a),(r>0?ia)&&(i+=r*Cc));for(var u,l=i;r>0?l>a:l1&&e.push(e.pop().concat(e.shift()))},result:function(){var n=e;return e=[],t=null,n}}}function Cl(t,e){return Mc(t[0]-e[0])=0;--a)i.point((l=u[a])[0],l[1]);else r(f.x,f.p.x,-1,i);f=f.p}u=(f=f.o).z,d=!d}while(!f.v);i.lineEnd()}}}function Ml(t){if(e=t.length){for(var e,n,r=0,i=t[0];++r=0?1:-1,E=T*k,C=E>kc,S=y*x;if(Nl.add(Dc(S*T*Fc(E),g*w+S*Oc(E))),o+=C?k+T*Cc:k,C^d>=n^b>=n){var A=du(hu(f),hu(v));gu(A);var M=du(a,A);gu(M);var N=(C^k>=0?-1:1)*Uc(M[2]);(r>N||r===N&&(A[0]||A[1]))&&(s+=C^k>=0?1:-1)}}return(o<-1e-6||o0){for(h||(i.polygonStart(),h=!0),i.lineStart(),t=0;t1&&2&c&&f.push(f.pop().concat(f.shift())),o.push(f.filter(Ll))}return f}}function Ll(t){return t.length>1}function Il(t,e){return((t=t.x)[0]<0?t[1]-Tc-xc:Tc-t[1])-((e=e.x)[0]<0?e[1]-Tc-xc:Tc-e[1])}const Rl=Bl((function(){return!0}),(function(t){var e,n=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),e=1},point:function(a,o){var s=a>0?kc:-kc,c=Mc(a-n);Mc(c-kc)0?Tc:-Tc),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),t.point(a,r),e=0):i!==s&&c>=kc&&(Mc(n-i)xc?Nc((Fc(e)*(a=Oc(r))*Fc(n)-Fc(r)*(i=Oc(e))*Fc(t))/(i*a*o)):(e+r)/2}(n,r,a,o),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),e=0),t.point(n=a,r=o),i=s},lineEnd:function(){t.lineEnd(),n=r=NaN},clean:function(){return 2-e}}}),(function(t,e,n,r){var i;if(null==t)i=n*Tc,r.point(-kc,i),r.point(0,i),r.point(kc,i),r.point(kc,0),r.point(kc,-i),r.point(0,-i),r.point(-kc,-i),r.point(-kc,0),r.point(-kc,i);else if(Mc(t[0]-e[0])>xc){var a=t[0]0,i=Mc(e)>xc;function a(t,n){return Oc(t)*Oc(n)>e}function o(t,n,r){var i=[1,0,0],a=du(hu(t),hu(n)),o=fu(a,a),s=a[0],c=o-s*s;if(!c)return!r&&t;var u=e*o/c,l=-e*s/c,h=du(i,a),f=yu(i,u);pu(f,yu(a,l));var d=h,p=fu(f,d),y=fu(d,d),g=p*p-y*(fu(f,f)-1);if(!(g<0)){var m=jc(g),v=yu(d,(-p-m)/y);if(pu(v,f),v=lu(v),!r)return v;var b,_=t[0],x=n[0],w=t[1],k=n[1];x<_&&(b=_,_=x,x=b);var T=x-_,E=Mc(T-kc)0^v[1]<(Mc(v[0]-_)kc^(_<=v[0]&&v[0]<=x)){var C=yu(d,(-p+m)/y);return pu(C,f),[v,lu(C)]}}}function s(e,n){var i=r?t:kc-t,a=0;return e<-i?a|=1:e>i&&(a|=2),n<-i?a|=4:n>i&&(a|=8),a}return Bl(a,(function(t){var e,n,c,u,l;return{lineStart:function(){u=c=!1,l=1},point:function(h,f){var d,p=[h,f],y=a(h,f),g=r?y?0:s(h,f):y?s(h+(h<0?kc:-kc),f):0;if(!e&&(u=c=y)&&t.lineStart(),y!==c&&(!(d=o(e,p))||Cl(e,d)||Cl(p,d))&&(p[2]=1),y!==c)l=0,y?(t.lineStart(),d=o(p,e),t.point(d[0],d[1])):(d=o(e,p),t.point(d[0],d[1],2),t.lineEnd()),e=d;else if(i&&e&&r^y){var m;g&n||!(m=o(p,e,!0))||(l=0,r?(t.lineStart(),t.point(m[0][0],m[0][1]),t.point(m[1][0],m[1][1]),t.lineEnd()):(t.point(m[1][0],m[1][1]),t.lineEnd(),t.lineStart(),t.point(m[0][0],m[0][1],3)))}!y||e&&Cl(e,p)||t.point(p[0],p[1]),e=p,c=y,n=g},lineEnd:function(){c&&t.lineEnd(),e=null},clean:function(){return l|(u&&c)<<1}}}),(function(e,r,i,a){wl(a,t,n,i,e,r)}),r?[0,-t]:[-kc,t-kc])}var Pl=1e9,jl=-Pl;function Yl(t,e,n,r){function i(i,a){return t<=i&&i<=n&&e<=a&&a<=r}function a(i,a,s,u){var l=0,h=0;if(null==i||(l=o(i,s))!==(h=o(a,s))||c(i,a)<0^s>0)do{u.point(0===l||3===l?t:n,l>1?r:e)}while((l=(l+s+4)%4)!==h);else u.point(a[0],a[1])}function o(r,i){return Mc(r[0]-t)0?0:3:Mc(r[0]-n)0?2:1:Mc(r[1]-e)0?1:0:i>0?3:2}function s(t,e){return c(t.x,e.x)}function c(t,e){var n=o(t,1),r=o(e,1);return n!==r?n-r:0===n?e[1]-t[1]:1===n?t[0]-e[0]:2===n?t[1]-e[1]:e[0]-t[0]}return function(o){var c,u,l,h,f,d,p,y,g,m,v,b=o,_=El(),x={point:w,lineStart:function(){x.point=k,u&&u.push(l=[]),m=!0,g=!1,p=y=NaN},lineEnd:function(){c&&(k(h,f),d&&g&&_.rejoin(),c.push(_.result())),x.point=w,g&&b.lineEnd()},polygonStart:function(){b=_,c=[],u=[],v=!0},polygonEnd:function(){var e=function(){for(var e=0,n=0,i=u.length;nr&&(f-a)*(r-o)>(d-o)*(t-a)&&++e:d<=r&&(f-a)*(r-o)<(d-o)*(t-a)&&--e;return e}(),n=v&&e,i=(c=P(c)).length;(n||i)&&(o.polygonStart(),n&&(o.lineStart(),a(null,null,1,o),o.lineEnd()),i&&Al(c,s,e,a,o),o.polygonEnd()),b=o,c=u=l=null}};function w(t,e){i(t,e)&&b.point(t,e)}function k(a,o){var s=i(a,o);if(u&&l.push([a,o]),m)h=a,f=o,d=s,m=!1,s&&(b.lineStart(),b.point(a,o));else if(s&&g)b.point(a,o);else{var c=[p=Math.max(jl,Math.min(Pl,p)),y=Math.max(jl,Math.min(Pl,y))],_=[a=Math.max(jl,Math.min(Pl,a)),o=Math.max(jl,Math.min(Pl,o))];!function(t,e,n,r,i,a){var o,s=t[0],c=t[1],u=0,l=1,h=e[0]-s,f=e[1]-c;if(o=n-s,h||!(o>0)){if(o/=h,h<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=i-s,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>u&&(u=o)}else if(h>0){if(o0)){if(o/=f,f<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=a-c,f||!(o<0)){if(o/=f,f<0){if(o>l)return;o>u&&(u=o)}else if(f>0){if(o0&&(t[0]=s+u*h,t[1]=c+u*f),l<1&&(e[0]=s+l*h,e[1]=c+l*f),!0}}}}}(c,_,t,e,n,r)?s&&(b.lineStart(),b.point(a,o),v=!1):(g||(b.lineStart(),b.point(c[0],c[1])),b.point(_[0],_[1]),s||b.lineEnd(),v=!1)}p=a,y=o,g=s}return x}}function zl(){var t,e,n,r=0,i=0,a=960,o=500;return n={stream:function(n){return t&&e===n?t:t=Yl(r,i,a,o)(e=n)},extent:function(s){return arguments.length?(r=+s[0][0],i=+s[0][1],a=+s[1][0],o=+s[1][1],t=e=null,n):[[r,i],[a,o]]}}}var Ul,ql,Hl,$l=mc(),Wl={sphere:Hc,point:Hc,lineStart:function(){Wl.point=Gl,Wl.lineEnd=Vl},lineEnd:Hc,polygonStart:Hc,polygonEnd:Hc};function Vl(){Wl.point=Wl.lineEnd=Hc}function Gl(t,e){Ul=t*=Ac,ql=Fc(e*=Ac),Hl=Oc(e),Wl.point=Xl}function Xl(t,e){t*=Ac;var n=Fc(e*=Ac),r=Oc(e),i=Mc(t-Ul),a=Oc(i),o=r*Fc(i),s=Hl*n-ql*r*a,c=ql*n+Hl*r*a;$l.add(Dc(jc(o*o+s*s),c)),Ul=t,ql=n,Hl=r}function Zl(t){return $l.reset(),Zc(t,Wl),+$l}var Ql=[null,null],Kl={type:"LineString",coordinates:Ql};function Jl(t,e){return Ql[0]=t,Ql[1]=e,Zl(Kl)}var th={Feature:function(t,e){return nh(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r0&&(i=Jl(t[a],t[a-1]))>0&&n<=i&&r<=i&&(n+r-i)*(1-Math.pow((n-r)/i,2))xc})).map(c)).concat(k(Bc(a/d)*d,i,d).filter((function(t){return Mc(t%y)>xc})).map(u))}return m.lines=function(){return v().map((function(t){return{type:"LineString",coordinates:t}}))},m.outline=function(){return{type:"Polygon",coordinates:[l(r).concat(h(o).slice(1),l(n).reverse().slice(1),h(s).reverse().slice(1))]}},m.extent=function(t){return arguments.length?m.extentMajor(t).extentMinor(t):m.extentMinor()},m.extentMajor=function(t){return arguments.length?(r=+t[0][0],n=+t[1][0],s=+t[0][1],o=+t[1][1],r>n&&(t=r,r=n,n=t),s>o&&(t=s,s=o,o=t),m.precision(g)):[[r,s],[n,o]]},m.extentMinor=function(n){return arguments.length?(e=+n[0][0],t=+n[1][0],a=+n[0][1],i=+n[1][1],e>t&&(n=e,e=t,t=n),a>i&&(n=a,a=i,i=n),m.precision(g)):[[e,a],[t,i]]},m.step=function(t){return arguments.length?m.stepMajor(t).stepMinor(t):m.stepMinor()},m.stepMajor=function(t){return arguments.length?(p=+t[0],y=+t[1],m):[p,y]},m.stepMinor=function(t){return arguments.length?(f=+t[0],d=+t[1],m):[f,d]},m.precision=function(f){return arguments.length?(g=+f,c=uh(a,i,90),u=lh(e,t,g),l=uh(s,o,90),h=lh(r,n,g),m):g},m.extentMajor([[-180,-89.999999],[180,89.999999]]).extentMinor([[-180,-80.000001],[180,80.000001]])}function fh(){return hh()()}function dh(t,e){var n=t[0]*Ac,r=t[1]*Ac,i=e[0]*Ac,a=e[1]*Ac,o=Oc(r),s=Fc(r),c=Oc(a),u=Fc(a),l=o*Oc(n),h=o*Fc(n),f=c*Oc(i),d=c*Fc(i),p=2*Uc(jc(qc(a-r)+o*c*qc(i-n))),y=Fc(p),g=p?function(t){var e=Fc(t*=p)/y,n=Fc(p-t)/y,r=n*l+e*f,i=n*h+e*d,a=n*s+e*u;return[Dc(i,r)*Sc,Dc(a,jc(r*r+i*i))*Sc]}:function(){return[n*Sc,r*Sc]};return g.distance=p,g}function ph(t){return t}var yh,gh,mh,vh,bh=mc(),_h=mc(),xh={point:Hc,lineStart:Hc,lineEnd:Hc,polygonStart:function(){xh.lineStart=wh,xh.lineEnd=Eh},polygonEnd:function(){xh.lineStart=xh.lineEnd=xh.point=Hc,bh.add(Mc(_h)),_h.reset()},result:function(){var t=bh/2;return bh.reset(),t}};function wh(){xh.point=kh}function kh(t,e){xh.point=Th,yh=mh=t,gh=vh=e}function Th(t,e){_h.add(vh*t-mh*e),mh=t,vh=e}function Eh(){Th(yh,gh)}const Ch=xh;var Sh=1/0,Ah=Sh,Mh=-Sh,Nh=Mh;const Dh={point:function(t,e){tMh&&(Mh=t),eNh&&(Nh=e)},lineStart:Hc,lineEnd:Hc,polygonStart:Hc,polygonEnd:Hc,result:function(){var t=[[Sh,Ah],[Mh,Nh]];return Mh=Nh=-(Ah=Sh=1/0),t}};var Oh,Bh,Lh,Ih,Rh=0,Fh=0,Ph=0,jh=0,Yh=0,zh=0,Uh=0,qh=0,Hh=0,$h={point:Wh,lineStart:Vh,lineEnd:Zh,polygonStart:function(){$h.lineStart=Qh,$h.lineEnd=Kh},polygonEnd:function(){$h.point=Wh,$h.lineStart=Vh,$h.lineEnd=Zh},result:function(){var t=Hh?[Uh/Hh,qh/Hh]:zh?[jh/zh,Yh/zh]:Ph?[Rh/Ph,Fh/Ph]:[NaN,NaN];return Rh=Fh=Ph=jh=Yh=zh=Uh=qh=Hh=0,t}};function Wh(t,e){Rh+=t,Fh+=e,++Ph}function Vh(){$h.point=Gh}function Gh(t,e){$h.point=Xh,Wh(Lh=t,Ih=e)}function Xh(t,e){var n=t-Lh,r=e-Ih,i=jc(n*n+r*r);jh+=i*(Lh+t)/2,Yh+=i*(Ih+e)/2,zh+=i,Wh(Lh=t,Ih=e)}function Zh(){$h.point=Wh}function Qh(){$h.point=Jh}function Kh(){tf(Oh,Bh)}function Jh(t,e){$h.point=tf,Wh(Oh=Lh=t,Bh=Ih=e)}function tf(t,e){var n=t-Lh,r=e-Ih,i=jc(n*n+r*r);jh+=i*(Lh+t)/2,Yh+=i*(Ih+e)/2,zh+=i,Uh+=(i=Ih*t-Lh*e)*(Lh+t),qh+=i*(Ih+e),Hh+=3*i,Wh(Lh=t,Ih=e)}const ef=$h;function nf(t){this._context=t}nf.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._context.moveTo(t,e),this._point=1;break;case 1:this._context.lineTo(t,e);break;default:this._context.moveTo(t+this._radius,e),this._context.arc(t,e,this._radius,0,Cc)}},result:Hc};var rf,af,of,sf,cf,uf=mc(),lf={point:Hc,lineStart:function(){lf.point=hf},lineEnd:function(){rf&&ff(af,of),lf.point=Hc},polygonStart:function(){rf=!0},polygonEnd:function(){rf=null},result:function(){var t=+uf;return uf.reset(),t}};function hf(t,e){lf.point=ff,af=sf=t,of=cf=e}function ff(t,e){sf-=t,cf-=e,uf.add(jc(sf*sf+cf*cf)),sf=t,cf=e}const df=lf;function pf(){this._string=[]}function yf(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function gf(t,e){var n,r,i=4.5;function a(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Zc(t,n(r))),r.result()}return a.area=function(t){return Zc(t,n(Ch)),Ch.result()},a.measure=function(t){return Zc(t,n(df)),df.result()},a.bounds=function(t){return Zc(t,n(Dh)),Dh.result()},a.centroid=function(t){return Zc(t,n(ef)),ef.result()},a.projection=function(e){return arguments.length?(n=null==e?(t=null,ph):(t=e).stream,a):t},a.context=function(t){return arguments.length?(r=null==t?(e=null,new pf):new nf(e=t),"function"!=typeof i&&r.pointRadius(i),a):e},a.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),a):i},a.projection(t).context(e)}function mf(t){return{stream:vf(t)}}function vf(t){return function(e){var n=new bf;for(var r in t)n[r]=t[r];return n.stream=e,n}}function bf(){}function _f(t,e,n){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Zc(n,t.stream(Dh)),e(Dh.result()),null!=r&&t.clipExtent(r),t}function xf(t,e,n){return _f(t,(function(n){var r=e[1][0]-e[0][0],i=e[1][1]-e[0][1],a=Math.min(r/(n[1][0]-n[0][0]),i/(n[1][1]-n[0][1])),o=+e[0][0]+(r-a*(n[1][0]+n[0][0]))/2,s=+e[0][1]+(i-a*(n[1][1]+n[0][1]))/2;t.scale(150*a).translate([o,s])}),n)}function wf(t,e,n){return xf(t,[[0,0],e],n)}function kf(t,e,n){return _f(t,(function(n){var r=+e,i=r/(n[1][0]-n[0][0]),a=(r-i*(n[1][0]+n[0][0]))/2,o=-i*n[0][1];t.scale(150*i).translate([a,o])}),n)}function Tf(t,e,n){return _f(t,(function(n){var r=+e,i=r/(n[1][1]-n[0][1]),a=-i*n[0][0],o=(r-i*(n[1][1]+n[0][1]))/2;t.scale(150*i).translate([a,o])}),n)}pf.prototype={_radius:4.5,_circle:yf(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._string.push("M",t,",",e),this._point=1;break;case 1:this._string.push("L",t,",",e);break;default:null==this._circle&&(this._circle=yf(this._radius)),this._string.push("M",t,",",e,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},bf.prototype={constructor:bf,point:function(t,e){this.stream.point(t,e)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Ef=Oc(30*Ac);function Cf(t,e){return+e?function(t,e){function n(r,i,a,o,s,c,u,l,h,f,d,p,y,g){var m=u-r,v=l-i,b=m*m+v*v;if(b>4*e&&y--){var _=o+f,x=s+d,w=c+p,k=jc(_*_+x*x+w*w),T=Uc(w/=k),E=Mc(Mc(w)-1)e||Mc((m*M+v*N)/b-.5)>.3||o*f+s*d+c*p2?t[2]%360*Ac:0,M()):[g*Sc,m*Sc,v*Sc]},S.angle=function(t){return arguments.length?(b=t%360*Ac,M()):b*Sc},S.reflectX=function(t){return arguments.length?(_=t?-1:1,M()):_<0},S.reflectY=function(t){return arguments.length?(x=t?-1:1,M()):x<0},S.precision=function(t){return arguments.length?(o=Cf(s,C=t*t),N()):jc(C)},S.fitExtent=function(t,e){return xf(S,t,e)},S.fitSize=function(t,e){return wf(S,t,e)},S.fitWidth=function(t,e){return kf(S,t,e)},S.fitHeight=function(t,e){return Tf(S,t,e)},function(){return e=t.apply(this,arguments),S.invert=e.invert&&A,M()}}function Of(t){var e=0,n=kc/3,r=Df(t),i=r(e,n);return i.parallels=function(t){return arguments.length?r(e=t[0]*Ac,n=t[1]*Ac):[e*Sc,n*Sc]},i}function Bf(t,e){var n=Fc(t),r=(n+Fc(e))/2;if(Mc(r)=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:o).invert(t)},l.stream=function(n){return t&&e===n?t:(r=[o.stream(e=n),s.stream(n),c.stream(n)],i=r.length,t={point:function(t,e){for(var n=-1;++n0?e<-Tc+xc&&(e=-Tc+xc):e>Tc-xc&&(e=Tc-xc);var n=i/Rc(Wf(e),r);return[n*Fc(r*t),i-n*Oc(r*t)]}return a.invert=function(t,e){var n=i-e,a=Pc(r)*jc(t*t+n*n),o=Dc(t,Mc(n))*Pc(n);return n*r<0&&(o-=kc*Pc(t)*Pc(n)),[o/r,2*Nc(Rc(i/a,1/r))-Tc]},a}function Gf(){return Of(Vf).scale(109.5).parallels([30,30])}function Xf(t,e){return[t,e]}function Zf(){return Nf(Xf).scale(152.63)}function Qf(t,e){var n=Oc(t),r=t===e?Fc(t):(n-Oc(e))/(e-t),i=n/r+t;if(Mc(r)2?t[2]+90:90]):[(t=n())[0],t[1],t[2]-90]},n([0,0,90]).scale(159.155)}function md(t,e){return t.parent===e.parent?1:2}function vd(t,e){return t+e.x}function bd(t,e){return Math.max(t,e.y)}function _d(){var t=md,e=1,n=1,r=!1;function i(i){var a,o=0;i.eachAfter((function(e){var n=e.children;n?(e.x=function(t){return t.reduce(vd,0)/t.length}(n),e.y=function(t){return 1+t.reduce(bd,0)}(n)):(e.x=a?o+=t(e,a):0,e.y=0,a=e)}));var s=function(t){for(var e;e=t.children;)t=e[0];return t}(i),c=function(t){for(var e;e=t.children;)t=e[e.length-1];return t}(i),u=s.x-t(s,c)/2,l=c.x+t(c,s)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*e,t.y=(i.y-t.y)*n}:function(t){t.x=(t.x-u)/(l-u)*e,t.y=(1-(i.y?t.y/i.y:1))*n})}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i}function xd(t){var e=0,n=t.children,r=n&&n.length;if(r)for(;--r>=0;)e+=n[r].value;else e=1;t.value=e}function wd(t,e){var n,r,i,a,o,s=new Cd(t),c=+t.value&&(s.value=t.value),u=[s];for(null==e&&(e=kd);n=u.pop();)if(c&&(n.value=+n.data.value),(i=e(n.data))&&(o=i.length))for(n.children=new Array(o),a=o-1;a>=0;--a)u.push(r=n.children[a]=new Cd(i[a])),r.parent=n,r.depth=n.depth+1;return s.eachBefore(Ed)}function kd(t){return t.children}function Td(t){t.data=t.data.data}function Ed(t){var e=0;do{t.height=e}while((t=t.parent)&&t.height<++e)}function Cd(t){this.data=t,this.depth=this.height=0,this.parent=null}id.invert=function(t,e){for(var n,r=e,i=r*r,a=i*i*i,o=0;o<12&&(a=(i=(r-=n=(r*(Jf+td*i+a*(ed+nd*i))-e)/(Jf+3*td*i+a*(7*ed+9*nd*i)))*r)*i*i,!(Mc(n)xc&&--i>0);return[t/(.8707+(a=r*r)*(a*(a*a*a*(.003971-.001529*a)-.013791)-.131979)),r]},hd.invert=Pf(Uc),dd.invert=Pf((function(t){return 2*Nc(t)})),yd.invert=function(t,e){return[-e,2*Nc(Lc(t))-Tc]},Cd.prototype=wd.prototype={constructor:Cd,count:function(){return this.eachAfter(xd)},each:function(t){var e,n,r,i,a=this,o=[a];do{for(e=o.reverse(),o=[];a=e.pop();)if(t(a),n=a.children)for(r=0,i=n.length;r=0;--n)i.push(e[n]);return this},sum:function(t){return this.eachAfter((function(e){for(var n=+t(e.data)||0,r=e.children,i=r&&r.length;--i>=0;)n+=r[i].value;e.value=n}))},sort:function(t){return this.eachBefore((function(e){e.children&&e.children.sort(t)}))},path:function(t){for(var e=this,n=function(t,e){if(t===e)return t;var n=t.ancestors(),r=e.ancestors(),i=null;for(t=n.pop(),e=r.pop();t===e;)i=t,t=n.pop(),e=r.pop();return i}(e,t),r=[e];e!==n;)e=e.parent,r.push(e);for(var i=r.length;t!==n;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e},descendants:function(){var t=[];return this.each((function(e){t.push(e)})),t},leaves:function(){var t=[];return this.eachBefore((function(e){e.children||t.push(e)})),t},links:function(){var t=this,e=[];return t.each((function(n){n!==t&&e.push({source:n.parent,target:n})})),e},copy:function(){return wd(this).eachBefore(Td)}};var Sd=Array.prototype.slice;function Ad(t){for(var e,n,r=0,i=(t=function(t){for(var e,n,r=t.length;r;)n=Math.random()*r--|0,e=t[r],t[r]=t[n],t[n]=e;return t}(Sd.call(t))).length,a=[];r0&&n*n>r*r+i*i}function Od(t,e){for(var n=0;n(o*=o)?(r=(u+o-i)/(2*u),a=Math.sqrt(Math.max(0,o/u-r*r)),n.x=t.x-r*s-a*c,n.y=t.y-r*c+a*s):(r=(u+i-o)/(2*u),a=Math.sqrt(Math.max(0,i/u-r*r)),n.x=e.x+r*s-a*c,n.y=e.y+r*c+a*s)):(n.x=e.x+n.r,n.y=e.y)}function Fd(t,e){var n=t.r+e.r-1e-6,r=e.x-t.x,i=e.y-t.y;return n>0&&n*n>r*r+i*i}function Pd(t){var e=t._,n=t.next._,r=e.r+n.r,i=(e.x*n.r+n.x*e.r)/r,a=(e.y*n.r+n.y*e.r)/r;return i*i+a*a}function jd(t){this._=t,this.next=null,this.previous=null}function Yd(t){if(!(i=t.length))return 0;var e,n,r,i,a,o,s,c,u,l,h;if((e=t[0]).x=0,e.y=0,!(i>1))return e.r;if(n=t[1],e.x=-n.r,n.x=e.r,n.y=0,!(i>2))return e.r+n.r;Rd(n,e,r=t[2]),e=new jd(e),n=new jd(n),r=new jd(r),e.next=r.previous=n,n.next=e.previous=r,r.next=n.previous=e;t:for(s=3;s0)throw new Error("cycle");return a}return n.id=function(e){return arguments.length?(t=qd(e),n):t},n.parentId=function(t){return arguments.length?(e=qd(t),n):e},n}function ap(t,e){return t.parent===e.parent?1:2}function op(t){var e=t.children;return e?e[0]:t.t}function sp(t){var e=t.children;return e?e[e.length-1]:t.t}function cp(t,e,n){var r=n/(e.i-t.i);e.c-=r,e.s+=n,t.c+=r,e.z+=n,e.m+=n}function up(t,e,n){return t.a.parent===e.parent?t.a:n}function lp(t,e){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=e}function hp(){var t=ap,e=1,n=1,r=null;function i(i){var c=function(t){for(var e,n,r,i,a,o=new lp(t,0),s=[o];e=s.pop();)if(r=e._.children)for(e.children=new Array(a=r.length),i=a-1;i>=0;--i)s.push(n=e.children[i]=new lp(r[i],i)),n.parent=e;return(o.parent=new lp(null,0)).children=[o],o}(i);if(c.eachAfter(a),c.parent.m=-c.z,c.eachBefore(o),r)i.eachBefore(s);else{var u=i,l=i,h=i;i.eachBefore((function(t){t.xl.x&&(l=t),t.depth>h.depth&&(h=t)}));var f=u===l?1:t(u,l)/2,d=f-u.x,p=e/(l.x+f+d),y=n/(h.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*y}))}return i}function a(e){var n=e.children,r=e.parent.children,i=e.i?r[e.i-1]:null;if(n){!function(t){for(var e,n=0,r=0,i=t.children,a=i.length;--a>=0;)(e=i[a]).z+=n,e.m+=n,n+=e.s+(r+=e.c)}(e);var a=(n[0].z+n[n.length-1].z)/2;i?(e.z=i.z+t(e._,i._),e.m=e.z-a):e.z=a}else i&&(e.z=i.z+t(e._,i._));e.parent.A=function(e,n,r){if(n){for(var i,a=e,o=e,s=n,c=a.parent.children[0],u=a.m,l=o.m,h=s.m,f=c.m;s=sp(s),a=op(a),s&&a;)c=op(c),(o=sp(o)).a=e,(i=s.z+h-a.z-u+t(s._,a._))>0&&(cp(up(s,e,r),e,i),u+=i,l+=i),h+=s.m,u+=a.m,f+=c.m,l+=o.m;s&&!sp(o)&&(o.t=s,o.m+=h-l),a&&!op(c)&&(c.t=a,c.m+=u-f,r=e)}return r}(e,i,e.parent.A||r[0])}function o(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function s(t){t.x*=e,t.y=t.depth*n}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i}function fp(t,e,n,r,i){for(var a,o=t.children,s=-1,c=o.length,u=t.value&&(i-n)/t.value;++sf&&(f=s),g=l*l*y,(d=Math.max(f/g,g/h))>p){l-=s;break}p=d}m.push(o={value:l,dice:c1?e:1)},n}(dp);function gp(){var t=yp,e=!1,n=1,r=1,i=[0],a=Hd,o=Hd,s=Hd,c=Hd,u=Hd;function l(t){return t.x0=t.y0=0,t.x1=n,t.y1=r,t.eachBefore(h),i=[0],e&&t.eachBefore(Qd),t}function h(e){var n=i[e.depth],r=e.x0+n,l=e.y0+n,h=e.x1-n,f=e.y1-n;h=n-1){var l=s[e];return l.x0=i,l.y0=a,l.x1=o,void(l.y1=c)}for(var h=u[e],f=r/2+h,d=e+1,p=n-1;d>>1;u[y]c-a){var v=(i*m+o*g)/r;t(e,d,g,i,a,v,c),t(d,n,m,v,a,o,c)}else{var b=(a*m+c*g)/r;t(e,d,g,i,a,o,b),t(d,n,m,i,b,o,c)}}(0,c,t.value,e,n,r,i)}function vp(t,e,n,r,i){(1&t.depth?fp:Kd)(t,e,n,r,i)}const bp=function t(e){function n(t,n,r,i,a){if((o=t._squarify)&&o.ratio===e)for(var o,s,c,u,l,h=-1,f=o.length,d=t.value;++h1?e:1)},n}(dp);function _p(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}}function xp(t,e){var n=fn(+t,+e);return function(t){var e=n(t);return e-360*Math.floor(e/360)}}function wp(t,e){return t=+t,e=+e,function(n){return Math.round(t*(1-n)+e*n)}}var kp=Math.SQRT2;function Tp(t){return((t=Math.exp(t))+1/t)/2}function Ep(t,e){var n,r,i=t[0],a=t[1],o=t[2],s=e[0],c=e[1],u=e[2],l=s-i,h=c-a,f=l*l+h*h;if(f<1e-12)r=Math.log(u/o)/kp,n=function(t){return[i+t*l,a+t*h,o*Math.exp(kp*t*r)]};else{var d=Math.sqrt(f),p=(u*u-o*o+4*f)/(2*o*2*d),y=(u*u-o*o-4*f)/(2*u*2*d),g=Math.log(Math.sqrt(p*p+1)-p),m=Math.log(Math.sqrt(y*y+1)-y);r=(m-g)/kp,n=function(t){var e,n=t*r,s=Tp(g),c=o/(2*d)*(s*(e=kp*n+g,((e=Math.exp(2*e))-1)/(e+1))-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+c*l,a+c*h,o*s/Tp(kp*n+g)]}}return n.duration=1e3*r,n}function Cp(t){return function(e,n){var r=t((e=rn(e)).h,(n=rn(n)).h),i=dn(e.s,n.s),a=dn(e.l,n.l),o=dn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.s=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const Sp=Cp(fn);var Ap=Cp(dn);function Mp(t,e){var n=dn((t=ba(t)).l,(e=ba(e)).l),r=dn(t.a,e.a),i=dn(t.b,e.b),a=dn(t.opacity,e.opacity);return function(e){return t.l=n(e),t.a=r(e),t.b=i(e),t.opacity=a(e),t+""}}function Np(t){return function(e,n){var r=t((e=Sa(e)).h,(n=Sa(n)).h),i=dn(e.c,n.c),a=dn(e.l,n.l),o=dn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const Dp=Np(fn);var Op=Np(dn);function Bp(t){return function e(n){function r(e,r){var i=t((e=Pa(e)).h,(r=Pa(r)).h),a=dn(e.s,r.s),o=dn(e.l,r.l),s=dn(e.opacity,r.opacity);return function(t){return e.h=i(t),e.s=a(t),e.l=o(Math.pow(t,n)),e.opacity=s(t),e+""}}return n=+n,r.gamma=e,r}(1)}const Lp=Bp(fn);var Ip=Bp(dn);function Rp(t,e){for(var n=0,r=e.length-1,i=e[0],a=new Array(r<0?0:r);n1&&Yp(t[n[r-2]],t[n[r-1]],t[i])<=0;)--r;n[r++]=i}return n.slice(0,r)}function qp(t){if((n=t.length)<3)return null;var e,n,r=new Array(n),i=new Array(n);for(e=0;e=0;--e)u.push(t[r[a[e]][2]]);for(e=+s;es!=u>s&&o<(c-n)*(s-r)/(u-r)+n&&(l=!l),c=n,u=r;return l}function $p(t){for(var e,n,r=-1,i=t.length,a=t[i-1],o=a[0],s=a[1],c=0;++r1);return t+n*a*Math.sqrt(-2*Math.log(i)/i)}}return n.source=t,n}(Wp),Xp=function t(e){function n(){var t=Gp.source(e).apply(this,arguments);return function(){return Math.exp(t())}}return n.source=t,n}(Wp),Zp=function t(e){function n(t){return function(){for(var n=0,r=0;rr&&(e=n,n=r,r=e),function(t){return Math.max(n,Math.min(r,t))}}function py(t,e,n){var r=t[0],i=t[1],a=e[0],o=e[1];return i2?yy:py,i=a=null,h}function h(e){return isNaN(e=+e)?n:(i||(i=r(o.map(t),s,c)))(t(u(e)))}return h.invert=function(n){return u(e((a||(a=r(s,o.map(t),kn)))(n)))},h.domain=function(t){return arguments.length?(o=ny.call(t,uy),u===hy||(u=dy(o)),l()):o.slice()},h.range=function(t){return arguments.length?(s=ry.call(t),l()):s.slice()},h.rangeRound=function(t){return s=ry.call(t),c=wp,l()},h.clamp=function(t){return arguments.length?(u=t?dy(o):hy,h):u!==hy},h.interpolate=function(t){return arguments.length?(c=t,l()):c},h.unknown=function(t){return arguments.length?(n=t,h):n},function(n,r){return t=n,e=r,l()}}function vy(t,e){return my()(t,e)}function by(t,e,n,r){var i,a=M(t,e,n);switch((r=nc(null==r?",f":r)).type){case"s":var o=Math.max(Math.abs(t),Math.abs(e));return null!=r.precision||isNaN(i=yc(a,o))||(r.precision=i),uc(r,o);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=gc(a,Math.max(Math.abs(t),Math.abs(e))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=pc(a))||(r.precision=i-2*("%"===r.type))}return cc(r)}function _y(t){var e=t.domain;return t.ticks=function(t){var n=e();return S(n[0],n[n.length-1],null==t?10:t)},t.tickFormat=function(t,n){var r=e();return by(r[0],r[r.length-1],null==t?10:t,n)},t.nice=function(n){null==n&&(n=10);var r,i=e(),a=0,o=i.length-1,s=i[a],c=i[o];return c0?r=A(s=Math.floor(s/r)*r,c=Math.ceil(c/r)*r,n):r<0&&(r=A(s=Math.ceil(s*r)/r,c=Math.floor(c*r)/r,n)),r>0?(i[a]=Math.floor(s/r)*r,i[o]=Math.ceil(c/r)*r,e(i)):r<0&&(i[a]=Math.ceil(s*r)/r,i[o]=Math.floor(c*r)/r,e(i)),t},t}function xy(){var t=vy(hy,hy);return t.copy=function(){return gy(t,xy())},Jp.apply(t,arguments),_y(t)}function wy(t){var e;function n(t){return isNaN(t=+t)?e:t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=ny.call(e,uy),n):t.slice()},n.unknown=function(t){return arguments.length?(e=t,n):e},n.copy=function(){return wy(t).unknown(e)},t=arguments.length?ny.call(t,uy):[0,1],_y(n)}function ky(t,e){var n,r=0,i=(t=t.slice()).length-1,a=t[r],o=t[i];return o0){for(;fc)break;y.push(h)}}else for(;f=1;--l)if(!((h=u*l)c)break;y.push(h)}}else y=S(f,d,Math.min(d-f,p)).map(n);return r?y.reverse():y},r.tickFormat=function(t,i){if(null==i&&(i=10===a?".0e":","),"function"!=typeof i&&(i=cc(i)),t===1/0)return i;null==t&&(t=10);var o=Math.max(1,a*t/r.ticks().length);return function(t){var r=t/n(Math.round(e(t)));return r*a0?r[i-1]:e[0],i=r?[i[r-1],n]:[i[o-1],i[o]]},o.unknown=function(e){return arguments.length?(t=e,o):o},o.thresholds=function(){return i.slice()},o.copy=function(){return qy().domain([e,n]).range(a).unknown(t)},Jp.apply(_y(o),arguments)}function Hy(){var t,e=[.5],n=[0,1],r=1;function i(i){return i<=i?n[u(e,i,0,r)]:t}return i.domain=function(t){return arguments.length?(e=ry.call(t),r=Math.min(e.length,n.length-1),i):e.slice()},i.range=function(t){return arguments.length?(n=ry.call(t),r=Math.min(e.length,n.length-1),i):n.slice()},i.invertExtent=function(t){var r=n.indexOf(t);return[e[r-1],e[r]]},i.unknown=function(e){return arguments.length?(t=e,i):t},i.copy=function(){return Hy().domain(e).range(n).unknown(t)},Jp.apply(i,arguments)}var $y=new Date,Wy=new Date;function Vy(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return $y.setTime(+e),Wy.setTime(+r),t($y),t(Wy),Math.floor(n($y,Wy))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}var Gy=Vy((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));Gy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Vy((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const Xy=Gy;var Zy=Gy.range,Qy=Vy((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,e){t.setMonth(t.getMonth()+e)}),(function(t,e){return e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()}));const Ky=Qy;var Jy=Qy.range,tg=6e4,eg=36e5,ng=6048e5;function rg(t){return Vy((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*tg)/ng}))}var ig=rg(0),ag=rg(1),og=rg(2),sg=rg(3),cg=rg(4),ug=rg(5),lg=rg(6),hg=ig.range,fg=ag.range,dg=og.range,pg=sg.range,yg=cg.range,gg=ug.range,mg=lg.range,vg=Vy((function(t){t.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*tg)/864e5}),(function(t){return t.getDate()-1}));const bg=vg;var _g=vg.range,xg=Vy((function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds()-t.getMinutes()*tg)}),(function(t,e){t.setTime(+t+e*eg)}),(function(t,e){return(e-t)/eg}),(function(t){return t.getHours()}));const wg=xg;var kg=xg.range,Tg=Vy((function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds())}),(function(t,e){t.setTime(+t+e*tg)}),(function(t,e){return(e-t)/tg}),(function(t){return t.getMinutes()}));const Eg=Tg;var Cg=Tg.range,Sg=Vy((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,e){t.setTime(+t+1e3*e)}),(function(t,e){return(e-t)/1e3}),(function(t){return t.getUTCSeconds()}));const Ag=Sg;var Mg=Sg.range,Ng=Vy((function(){}),(function(t,e){t.setTime(+t+e)}),(function(t,e){return e-t}));Ng.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Vy((function(e){e.setTime(Math.floor(e/t)*t)}),(function(e,n){e.setTime(+e+n*t)}),(function(e,n){return(n-e)/t})):Ng:null};const Dg=Ng;var Og=Ng.range;function Bg(t){return Vy((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/ng}))}var Lg=Bg(0),Ig=Bg(1),Rg=Bg(2),Fg=Bg(3),Pg=Bg(4),jg=Bg(5),Yg=Bg(6),zg=Lg.range,Ug=Ig.range,qg=Rg.range,Hg=Fg.range,$g=Pg.range,Wg=jg.range,Vg=Yg.range,Gg=Vy((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/864e5}),(function(t){return t.getUTCDate()-1}));const Xg=Gg;var Zg=Gg.range,Qg=Vy((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Qg.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Vy((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const Kg=Qg;var Jg=Qg.range;function tm(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function em(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function nm(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}function rm(t){var e=t.dateTime,n=t.date,r=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,c=t.shortMonths,u=ym(i),l=gm(i),h=ym(a),f=gm(a),d=ym(o),p=gm(o),y=ym(s),g=gm(s),m=ym(c),v=gm(c),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:Fm,e:Fm,f:Um,g:Jm,G:ev,H:Pm,I:jm,j:Ym,L:zm,m:qm,M:Hm,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Tv,s:Ev,S:$m,u:Wm,U:Vm,V:Xm,w:Zm,W:Qm,x:null,X:null,y:Km,Y:tv,Z:nv,"%":kv},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:rv,e:rv,f:cv,g:bv,G:xv,H:iv,I:av,j:ov,L:sv,m:uv,M:lv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Tv,s:Ev,S:hv,u:fv,U:dv,V:yv,w:gv,W:mv,x:null,X:null,y:vv,Y:_v,Z:wv,"%":kv},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p[r[0].toLowerCase()],n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f[r[0].toLowerCase()],n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v[r[0].toLowerCase()],n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g[r[0].toLowerCase()],n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:Sm,e:Sm,f:Bm,g:km,G:wm,H:Mm,I:Mm,j:Am,L:Om,m:Cm,M:Nm,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l[r[0].toLowerCase()],n+r[0].length):-1},q:Em,Q:Im,s:Rm,S:Dm,u:vm,U:bm,V:_m,w:mm,W:xm,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:km,Y:wm,Z:Tm,"%":Lm};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=em(nm(a.y,0,1))).getUTCDay(),r=i>4||0===i?Ig.ceil(r):Ig(r),r=Xg.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=tm(nm(a.y,0,1))).getDay(),r=i>4||0===i?ag.ceil(r):ag(r),r=bg.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?em(nm(a.y,0,1)).getUTCDay():tm(nm(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,em(a)):tm(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in um?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}var im,am,om,sm,cm,um={"-":"",_:" ",0:"0"},lm=/^\s*\d+/,hm=/^%/,fm=/[\\^$*+?|[\]().{}]/g;function dm(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",a=i.length;return r+(a68?1900:2e3),n+r[0].length):-1}function Tm(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Em(t,e,n){var r=lm.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function Cm(t,e,n){var r=lm.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Sm(t,e,n){var r=lm.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Am(t,e,n){var r=lm.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Mm(t,e,n){var r=lm.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function Nm(t,e,n){var r=lm.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Dm(t,e,n){var r=lm.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Om(t,e,n){var r=lm.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Bm(t,e,n){var r=lm.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function Lm(t,e,n){var r=hm.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Im(t,e,n){var r=lm.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Rm(t,e,n){var r=lm.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Fm(t,e){return dm(t.getDate(),e,2)}function Pm(t,e){return dm(t.getHours(),e,2)}function jm(t,e){return dm(t.getHours()%12||12,e,2)}function Ym(t,e){return dm(1+bg.count(Xy(t),t),e,3)}function zm(t,e){return dm(t.getMilliseconds(),e,3)}function Um(t,e){return zm(t,e)+"000"}function qm(t,e){return dm(t.getMonth()+1,e,2)}function Hm(t,e){return dm(t.getMinutes(),e,2)}function $m(t,e){return dm(t.getSeconds(),e,2)}function Wm(t){var e=t.getDay();return 0===e?7:e}function Vm(t,e){return dm(ig.count(Xy(t)-1,t),e,2)}function Gm(t){var e=t.getDay();return e>=4||0===e?cg(t):cg.ceil(t)}function Xm(t,e){return t=Gm(t),dm(cg.count(Xy(t),t)+(4===Xy(t).getDay()),e,2)}function Zm(t){return t.getDay()}function Qm(t,e){return dm(ag.count(Xy(t)-1,t),e,2)}function Km(t,e){return dm(t.getFullYear()%100,e,2)}function Jm(t,e){return dm((t=Gm(t)).getFullYear()%100,e,2)}function tv(t,e){return dm(t.getFullYear()%1e4,e,4)}function ev(t,e){var n=t.getDay();return dm((t=n>=4||0===n?cg(t):cg.ceil(t)).getFullYear()%1e4,e,4)}function nv(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+dm(e/60|0,"0",2)+dm(e%60,"0",2)}function rv(t,e){return dm(t.getUTCDate(),e,2)}function iv(t,e){return dm(t.getUTCHours(),e,2)}function av(t,e){return dm(t.getUTCHours()%12||12,e,2)}function ov(t,e){return dm(1+Xg.count(Kg(t),t),e,3)}function sv(t,e){return dm(t.getUTCMilliseconds(),e,3)}function cv(t,e){return sv(t,e)+"000"}function uv(t,e){return dm(t.getUTCMonth()+1,e,2)}function lv(t,e){return dm(t.getUTCMinutes(),e,2)}function hv(t,e){return dm(t.getUTCSeconds(),e,2)}function fv(t){var e=t.getUTCDay();return 0===e?7:e}function dv(t,e){return dm(Lg.count(Kg(t)-1,t),e,2)}function pv(t){var e=t.getUTCDay();return e>=4||0===e?Pg(t):Pg.ceil(t)}function yv(t,e){return t=pv(t),dm(Pg.count(Kg(t),t)+(4===Kg(t).getUTCDay()),e,2)}function gv(t){return t.getUTCDay()}function mv(t,e){return dm(Ig.count(Kg(t)-1,t),e,2)}function vv(t,e){return dm(t.getUTCFullYear()%100,e,2)}function bv(t,e){return dm((t=pv(t)).getUTCFullYear()%100,e,2)}function _v(t,e){return dm(t.getUTCFullYear()%1e4,e,4)}function xv(t,e){var n=t.getUTCDay();return dm((t=n>=4||0===n?Pg(t):Pg.ceil(t)).getUTCFullYear()%1e4,e,4)}function wv(){return"+0000"}function kv(){return"%"}function Tv(t){return+t}function Ev(t){return Math.floor(+t/1e3)}function Cv(t){return im=rm(t),am=im.format,om=im.parse,sm=im.utcFormat,cm=im.utcParse,im}Cv({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Sv=31536e6;function Av(t){return new Date(t)}function Mv(t){return t instanceof Date?+t:+new Date(+t)}function Nv(t,e,n,r,i,o,s,c,u){var l=vy(hy,hy),h=l.invert,f=l.domain,d=u(".%L"),p=u(":%S"),y=u("%I:%M"),g=u("%I %p"),m=u("%a %d"),v=u("%b %d"),b=u("%B"),_=u("%Y"),x=[[s,1,1e3],[s,5,5e3],[s,15,15e3],[s,30,3e4],[o,1,6e4],[o,5,3e5],[o,15,9e5],[o,30,18e5],[i,1,36e5],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,864e5],[r,2,1728e5],[n,1,6048e5],[e,1,2592e6],[e,3,7776e6],[t,1,Sv]];function w(a){return(s(a)1)&&(t-=Math.floor(t));var e=Math.abs(t-.5);return v_.h=360*t-100,v_.s=1.5-1.5*e,v_.l=.8-.9*e,v_+""}var __=Ze(),x_=Math.PI/3,w_=2*Math.PI/3;function k_(t){var e;return t=(.5-t)*Math.PI,__.r=255*(e=Math.sin(t))*e,__.g=255*(e=Math.sin(t+x_))*e,__.b=255*(e=Math.sin(t+w_))*e,__+""}function T_(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"}function E_(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}}const C_=E_(nb("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));var S_=E_(nb("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),A_=E_(nb("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),M_=E_(nb("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function N_(t){return Te(ie(t).call(document.documentElement))}var D_=0;function O_(){return new B_}function B_(){this._="@"+(++D_).toString(36)}function L_(t){return"string"==typeof t?new xe([document.querySelectorAll(t)],[document.documentElement]):new xe([null==t?[]:t],_e)}function I_(t,e){null==e&&(e=Mn().touches);for(var n=0,r=e?e.length:0,i=new Array(r);n1?0:t<-1?$_:Math.acos(t)}function X_(t){return t>=1?W_:t<=-1?-W_:Math.asin(t)}function Z_(t){return t.innerRadius}function Q_(t){return t.outerRadius}function K_(t){return t.startAngle}function J_(t){return t.endAngle}function tx(t){return t&&t.padAngle}function ex(t,e,n,r,i,a,o,s){var c=n-t,u=r-e,l=o-i,h=s-a,f=h*c-l*u;if(!(f*fN*N+D*D&&(T=C,E=S),{cx:T,cy:E,x01:-l,y01:-h,x11:T*(i/x-1),y11:E*(i/x-1)}}function rx(){var t=Z_,e=Q_,n=R_(0),r=null,i=K_,a=J_,o=tx,s=null;function c(){var c,u,l=+t.apply(this,arguments),h=+e.apply(this,arguments),f=i.apply(this,arguments)-W_,d=a.apply(this,arguments)-W_,p=F_(d-f),y=d>f;if(s||(s=c=$i()),hH_)if(p>V_-H_)s.moveTo(h*j_(f),h*U_(f)),s.arc(0,0,h,f,d,!y),l>H_&&(s.moveTo(l*j_(d),l*U_(d)),s.arc(0,0,l,d,f,y));else{var g,m,v=f,b=d,_=f,x=d,w=p,k=p,T=o.apply(this,arguments)/2,E=T>H_&&(r?+r.apply(this,arguments):q_(l*l+h*h)),C=z_(F_(h-l)/2,+n.apply(this,arguments)),S=C,A=C;if(E>H_){var M=X_(E/l*U_(T)),N=X_(E/h*U_(T));(w-=2*M)>H_?(_+=M*=y?1:-1,x-=M):(w=0,_=x=(f+d)/2),(k-=2*N)>H_?(v+=N*=y?1:-1,b-=N):(k=0,v=b=(f+d)/2)}var D=h*j_(v),O=h*U_(v),B=l*j_(x),L=l*U_(x);if(C>H_){var I,R=h*j_(b),F=h*U_(b),P=l*j_(_),j=l*U_(_);if(p<$_&&(I=ex(D,O,P,j,R,F,B,L))){var Y=D-I[0],z=O-I[1],U=R-I[0],q=F-I[1],H=1/U_(G_((Y*U+z*q)/(q_(Y*Y+z*z)*q_(U*U+q*q)))/2),$=q_(I[0]*I[0]+I[1]*I[1]);S=z_(C,(l-$)/(H-1)),A=z_(C,(h-$)/(H+1))}}k>H_?A>H_?(g=nx(P,j,D,O,h,A,y),m=nx(R,F,B,L,h,A,y),s.moveTo(g.cx+g.x01,g.cy+g.y01),AH_&&w>H_?S>H_?(g=nx(B,L,R,F,l,-S,y),m=nx(D,O,P,j,l,-S,y),s.lineTo(g.cx+g.x01,g.cy+g.y01),S=l;--h)s.point(g[h],m[h]);s.lineEnd(),s.areaEnd()}y&&(g[u]=+t(f,u,c),m[u]=+n(f,u,c),s.point(e?+e(f,u,c):g[u],r?+r(f,u,c):m[u]))}if(d)return s=null,d+""||null}function u(){return cx().defined(i).curve(o).context(a)}return c.x=function(n){return arguments.length?(t="function"==typeof n?n:R_(+n),e=null,c):t},c.x0=function(e){return arguments.length?(t="function"==typeof e?e:R_(+e),c):t},c.x1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:R_(+t),c):e},c.y=function(t){return arguments.length?(n="function"==typeof t?t:R_(+t),r=null,c):n},c.y0=function(t){return arguments.length?(n="function"==typeof t?t:R_(+t),c):n},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:R_(+t),c):r},c.lineX0=c.lineY0=function(){return u().x(t).y(n)},c.lineY1=function(){return u().x(t).y(r)},c.lineX1=function(){return u().x(e).y(n)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:R_(!!t),c):i},c.curve=function(t){return arguments.length?(o=t,null!=a&&(s=o(a)),c):o},c.context=function(t){return arguments.length?(null==t?a=s=null:s=o(a=t),c):a},c}function lx(t,e){return et?1:e>=t?0:NaN}function hx(t){return t}function fx(){var t=hx,e=lx,n=null,r=R_(0),i=R_(V_),a=R_(0);function o(o){var s,c,u,l,h,f=o.length,d=0,p=new Array(f),y=new Array(f),g=+r.apply(this,arguments),m=Math.min(V_,Math.max(-V_,i.apply(this,arguments)-g)),v=Math.min(Math.abs(m)/f,a.apply(this,arguments)),b=v*(m<0?-1:1);for(s=0;s0&&(d+=h);for(null!=e?p.sort((function(t,n){return e(y[t],y[n])})):null!=n&&p.sort((function(t,e){return n(o[t],o[e])})),s=0,u=d?(m-f*b)/d:0;s0?h*u:0)+b,y[c]={data:o[c],index:s,value:h,startAngle:g,endAngle:l,padAngle:v};return y}return o.value=function(e){return arguments.length?(t="function"==typeof e?e:R_(+e),o):t},o.sortValues=function(t){return arguments.length?(e=t,n=null,o):e},o.sort=function(t){return arguments.length?(n=t,e=null,o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:R_(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:R_(+t),o):i},o.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:R_(+t),o):a},o}ix.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e)}}};var dx=yx(ax);function px(t){this._curve=t}function yx(t){function e(e){return new px(t(e))}return e._curve=t,e}function gx(t){var e=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?e(yx(t)):e()._curve},t}function mx(){return gx(cx().curve(dx))}function vx(){var t=ux().curve(dx),e=t.curve,n=t.lineX0,r=t.lineX1,i=t.lineY0,a=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return gx(n())},delete t.lineX0,t.lineEndAngle=function(){return gx(r())},delete t.lineX1,t.lineInnerRadius=function(){return gx(i())},delete t.lineY0,t.lineOuterRadius=function(){return gx(a())},delete t.lineY1,t.curve=function(t){return arguments.length?e(yx(t)):e()._curve},t}function bx(t,e){return[(e=+e)*Math.cos(t-=Math.PI/2),e*Math.sin(t)]}px.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,e){this._curve.point(e*Math.sin(t),e*-Math.cos(t))}};var _x=Array.prototype.slice;function xx(t){return t.source}function wx(t){return t.target}function kx(t){var e=xx,n=wx,r=ox,i=sx,a=null;function o(){var o,s=_x.call(arguments),c=e.apply(this,s),u=n.apply(this,s);if(a||(a=o=$i()),t(a,+r.apply(this,(s[0]=c,s)),+i.apply(this,s),+r.apply(this,(s[0]=u,s)),+i.apply(this,s)),o)return a=null,o+""||null}return o.source=function(t){return arguments.length?(e=t,o):e},o.target=function(t){return arguments.length?(n=t,o):n},o.x=function(t){return arguments.length?(r="function"==typeof t?t:R_(+t),o):r},o.y=function(t){return arguments.length?(i="function"==typeof t?t:R_(+t),o):i},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o}function Tx(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e=(e+r)/2,n,e,i,r,i)}function Ex(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e,n=(n+i)/2,r,n,r,i)}function Cx(t,e,n,r,i){var a=bx(e,n),o=bx(e,n=(n+i)/2),s=bx(r,n),c=bx(r,i);t.moveTo(a[0],a[1]),t.bezierCurveTo(o[0],o[1],s[0],s[1],c[0],c[1])}function Sx(){return kx(Tx)}function Ax(){return kx(Ex)}function Mx(){var t=kx(Cx);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t}const Nx={draw:function(t,e){var n=Math.sqrt(e/$_);t.moveTo(n,0),t.arc(0,0,n,0,V_)}},Dx={draw:function(t,e){var n=Math.sqrt(e/5)/2;t.moveTo(-3*n,-n),t.lineTo(-n,-n),t.lineTo(-n,-3*n),t.lineTo(n,-3*n),t.lineTo(n,-n),t.lineTo(3*n,-n),t.lineTo(3*n,n),t.lineTo(n,n),t.lineTo(n,3*n),t.lineTo(-n,3*n),t.lineTo(-n,n),t.lineTo(-3*n,n),t.closePath()}};var Ox=Math.sqrt(1/3),Bx=2*Ox;const Lx={draw:function(t,e){var n=Math.sqrt(e/Bx),r=n*Ox;t.moveTo(0,-n),t.lineTo(r,0),t.lineTo(0,n),t.lineTo(-r,0),t.closePath()}};var Ix=Math.sin($_/10)/Math.sin(7*$_/10),Rx=Math.sin(V_/10)*Ix,Fx=-Math.cos(V_/10)*Ix;const Px={draw:function(t,e){var n=Math.sqrt(.8908130915292852*e),r=Rx*n,i=Fx*n;t.moveTo(0,-n),t.lineTo(r,i);for(var a=1;a<5;++a){var o=V_*a/5,s=Math.cos(o),c=Math.sin(o);t.lineTo(c*n,-s*n),t.lineTo(s*r-c*i,c*r+s*i)}t.closePath()}},jx={draw:function(t,e){var n=Math.sqrt(e),r=-n/2;t.rect(r,r,n,n)}};var Yx=Math.sqrt(3);const zx={draw:function(t,e){var n=-Math.sqrt(e/(3*Yx));t.moveTo(0,2*n),t.lineTo(-Yx*n,-n),t.lineTo(Yx*n,-n),t.closePath()}};var Ux=-.5,qx=Math.sqrt(3)/2,Hx=1/Math.sqrt(12),$x=3*(Hx/2+1);const Wx={draw:function(t,e){var n=Math.sqrt(e/$x),r=n/2,i=n*Hx,a=r,o=n*Hx+n,s=-a,c=o;t.moveTo(r,i),t.lineTo(a,o),t.lineTo(s,c),t.lineTo(Ux*r-qx*i,qx*r+Ux*i),t.lineTo(Ux*a-qx*o,qx*a+Ux*o),t.lineTo(Ux*s-qx*c,qx*s+Ux*c),t.lineTo(Ux*r+qx*i,Ux*i-qx*r),t.lineTo(Ux*a+qx*o,Ux*o-qx*a),t.lineTo(Ux*s+qx*c,Ux*c-qx*s),t.closePath()}};var Vx=[Nx,Dx,Lx,jx,Px,zx,Wx];function Gx(){var t=R_(Nx),e=R_(64),n=null;function r(){var r;if(n||(n=r=$i()),t.apply(this,arguments).draw(n,+e.apply(this,arguments)),r)return n=null,r+""||null}return r.type=function(e){return arguments.length?(t="function"==typeof e?e:R_(e),r):t},r.size=function(t){return arguments.length?(e="function"==typeof t?t:R_(+t),r):e},r.context=function(t){return arguments.length?(n=null==t?null:t,r):n},r}function Xx(){}function Zx(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function Qx(t){this._context=t}function Kx(t){return new Qx(t)}function Jx(t){this._context=t}function tw(t){return new Jx(t)}function ew(t){this._context=t}function nw(t){return new ew(t)}function rw(t,e){this._basis=new Qx(t),this._beta=e}Qx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Zx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Zx(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},Jx.prototype={areaStart:Xx,areaEnd:Xx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:Zx(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},ew.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(n,r):this._context.moveTo(n,r);break;case 3:this._point=4;default:Zx(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},rw.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,n=t.length-1;if(n>0)for(var r,i=t[0],a=e[0],o=t[n]-i,s=e[n]-a,c=-1;++c<=n;)r=c/n,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*o),this._beta*e[c]+(1-this._beta)*(a+r*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};const iw=function t(e){function n(t){return 1===e?new Qx(t):new rw(t,e)}return n.beta=function(e){return t(+e)},n}(.85);function aw(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function ow(t,e){this._context=t,this._k=(1-e)/6}ow.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:aw(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:aw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const sw=function t(e){function n(t){return new ow(t,e)}return n.tension=function(e){return t(+e)},n}(0);function cw(t,e){this._context=t,this._k=(1-e)/6}cw.prototype={areaStart:Xx,areaEnd:Xx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:aw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const uw=function t(e){function n(t){return new cw(t,e)}return n.tension=function(e){return t(+e)},n}(0);function lw(t,e){this._context=t,this._k=(1-e)/6}lw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:aw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const hw=function t(e){function n(t){return new lw(t,e)}return n.tension=function(e){return t(+e)},n}(0);function fw(t,e,n){var r=t._x1,i=t._y1,a=t._x2,o=t._y2;if(t._l01_a>H_){var s=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*s-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*s-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>H_){var u=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,l=3*t._l23_a*(t._l23_a+t._l12_a);a=(a*u+t._x1*t._l23_2a-e*t._l12_2a)/l,o=(o*u+t._y1*t._l23_2a-n*t._l12_2a)/l}t._context.bezierCurveTo(r,i,a,o,t._x2,t._y2)}function dw(t,e){this._context=t,this._alpha=e}dw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:fw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const pw=function t(e){function n(t){return e?new dw(t,e):new ow(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function yw(t,e){this._context=t,this._alpha=e}yw.prototype={areaStart:Xx,areaEnd:Xx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:fw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const gw=function t(e){function n(t){return e?new yw(t,e):new cw(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function mw(t,e){this._context=t,this._alpha=e}mw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:fw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const vw=function t(e){function n(t){return e?new mw(t,e):new lw(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function bw(t){this._context=t}function _w(t){return new bw(t)}function xw(t){return t<0?-1:1}function ww(t,e,n){var r=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(r||i<0&&-0),o=(n-t._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(xw(a)+xw(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function kw(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function Tw(t,e,n){var r=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-r)/3;t._context.bezierCurveTo(r+s,i+s*e,a-s,o-s*n,a,o)}function Ew(t){this._context=t}function Cw(t){this._context=new Sw(t)}function Sw(t){this._context=t}function Aw(t){return new Ew(t)}function Mw(t){return new Cw(t)}function Nw(t){this._context=t}function Dw(t){var e,n,r=t.length-1,i=new Array(r),a=new Array(r),o=new Array(r);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e1)for(var n,r,i,a=1,o=t[e[0]],s=o.length;a=0;)n[e]=e;return n}function jw(t,e){return t[e]}function Yw(){var t=R_([]),e=Pw,n=Fw,r=jw;function i(i){var a,o,s=t.apply(this,arguments),c=i.length,u=s.length,l=new Array(u);for(a=0;a0){for(var n,r,i,a=0,o=t[0].length;a0)for(var n,r,i,a,o,s,c=0,u=t[e[0]].length;c0?(r[0]=a,r[1]=a+=i):i<0?(r[1]=o,r[0]=o+=i):(r[0]=0,r[1]=i)}function qw(t,e){if((n=t.length)>0){for(var n,r=0,i=t[e[0]],a=i.length;r0&&(r=(n=t[e[0]]).length)>0){for(var n,r,i,a=0,o=1;oa&&(a=e,r=n);return r}function Vw(t){var e=t.map(Gw);return Pw(t).sort((function(t,n){return e[t]-e[n]}))}function Gw(t){for(var e,n=0,r=-1,i=t.length;++r=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var Kw="%Y-%m-%dT%H:%M:%S.%LZ";const Jw=Date.prototype.toISOString?function(t){return t.toISOString()}:sm(Kw),tk=+new Date("2000-01-01T00:00:00.000Z")?function(t){var e=new Date(t);return isNaN(e)?null:e}:cm(Kw);function ek(t,e,n){var r=new $n,i=e;return null==e?(r.restart(t,e,n),r):(e=+e,n=null==n?qn():+n,r.restart((function a(o){o+=i,r.restart(a,i+=e,n),t(o)}),e,n),r)}function nk(t){return function(){return t}}function rk(t){return t[0]}function ik(t){return t[1]}function ak(){this._=null}function ok(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function sk(t,e){var n=e,r=e.R,i=n.U;i?i.L===n?i.L=r:i.R=r:t._=r,r.U=i,n.U=r,n.R=r.L,n.R&&(n.R.U=n),r.L=n}function ck(t,e){var n=e,r=e.L,i=n.U;i?i.L===n?i.L=r:i.R=r:t._=r,r.U=i,n.U=r,n.L=r.R,n.L&&(n.L.U=n),r.R=n}function uk(t){for(;t.L;)t=t.L;return t}ak.prototype={constructor:ak,insert:function(t,e){var n,r,i;if(t){if(e.P=t,e.N=t.N,t.N&&(t.N.P=e),t.N=e,t.R){for(t=t.R;t.L;)t=t.L;t.L=e}else t.R=e;n=t}else this._?(t=uk(this._),e.P=null,e.N=t,t.P=t.L=e,n=t):(e.P=e.N=null,this._=e,n=null);for(e.L=e.R=null,e.U=n,e.C=!0,t=e;n&&n.C;)n===(r=n.U).L?(i=r.R)&&i.C?(n.C=i.C=!1,r.C=!0,t=r):(t===n.R&&(sk(this,n),n=(t=n).U),n.C=!1,r.C=!0,ck(this,r)):(i=r.L)&&i.C?(n.C=i.C=!1,r.C=!0,t=r):(t===n.L&&(ck(this,n),n=(t=n).U),n.C=!1,r.C=!0,sk(this,r)),n=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var e,n,r,i=t.U,a=t.L,o=t.R;if(n=a?o?uk(o):a:o,i?i.L===t?i.L=n:i.R=n:this._=n,a&&o?(r=n.C,n.C=t.C,n.L=a,a.U=n,n!==o?(i=n.U,n.U=t.U,t=n.R,i.L=t,n.R=o,o.U=n):(n.U=i,i=n,t=n.R)):(r=t.C,t=n),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((e=i.R).C&&(e.C=!1,i.C=!0,sk(this,i),e=i.R),e.L&&e.L.C||e.R&&e.R.C){e.R&&e.R.C||(e.L.C=!1,e.C=!0,ck(this,e),e=i.R),e.C=i.C,i.C=e.R.C=!1,sk(this,i),t=this._;break}}else if((e=i.L).C&&(e.C=!1,i.C=!0,ck(this,i),e=i.L),e.L&&e.L.C||e.R&&e.R.C){e.L&&e.L.C||(e.R.C=!1,e.C=!0,sk(this,e),e=i.L),e.C=i.C,i.C=e.L.C=!1,ck(this,i),t=this._;break}e.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};const lk=ak;function hk(t,e,n,r){var i=[null,null],a=Ik.push(i)-1;return i.left=t,i.right=e,n&&dk(i,t,e,n),r&&dk(i,e,t,r),Bk[t.index].halfedges.push(a),Bk[e.index].halfedges.push(a),i}function fk(t,e,n){var r=[e,n];return r.left=t,r}function dk(t,e,n,r){t[0]||t[1]?t.left===n?t[1]=r:t[0]=r:(t[0]=r,t.left=e,t.right=n)}function pk(t,e,n,r,i){var a,o=t[0],s=t[1],c=o[0],u=o[1],l=0,h=1,f=s[0]-c,d=s[1]-u;if(a=e-c,f||!(a>0)){if(a/=f,f<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=r-c,f||!(a<0)){if(a/=f,f<0){if(a>h)return;a>l&&(l=a)}else if(f>0){if(a0)){if(a/=d,d<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=i-u,d||!(a<0)){if(a/=d,d<0){if(a>h)return;a>l&&(l=a)}else if(d>0){if(a0||h<1)||(l>0&&(t[0]=[c+l*f,u+l*d]),h<1&&(t[1]=[c+h*f,u+h*d]),!0)}}}}}function yk(t,e,n,r,i){var a=t[1];if(a)return!0;var o,s,c=t[0],u=t.left,l=t.right,h=u[0],f=u[1],d=l[0],p=l[1],y=(h+d)/2,g=(f+p)/2;if(p===f){if(y=r)return;if(h>d){if(c){if(c[1]>=i)return}else c=[y,n];a=[y,i]}else{if(c){if(c[1]1)if(h>d){if(c){if(c[1]>=i)return}else c=[(n-s)/o,n];a=[(i-s)/o,i]}else{if(c){if(c[1]=r)return}else c=[e,o*e+s];a=[r,o*r+s]}else{if(c){if(c[0]=-Fk)){var d=c*c+u*u,p=l*l+h*h,y=(h*d-u*p)/f,g=(c*p-l*d)/f,m=_k.pop()||new xk;m.arc=t,m.site=i,m.x=y+o,m.y=(m.cy=g+s)+Math.sqrt(y*y+g*g),t.circle=m;for(var v=null,b=Lk._;b;)if(m.yRk)s=s.L;else{if(!((i=a-Dk(s,o))>Rk)){r>-Rk?(e=s.P,n=s):i>-Rk?(e=s,n=s.N):e=n=s;break}if(!s.R){e=s;break}s=s.R}!function(t){Bk[t.index]={site:t,halfedges:[]}}(t);var c=Ck(t);if(Ok.insert(e,c),e||n){if(e===n)return kk(e),n=Ck(e.site),Ok.insert(c,n),c.edge=n.edge=hk(e.site,c.site),wk(e),void wk(n);if(n){kk(e),kk(n);var u=e.site,l=u[0],h=u[1],f=t[0]-l,d=t[1]-h,p=n.site,y=p[0]-l,g=p[1]-h,m=2*(f*g-d*y),v=f*f+d*d,b=y*y+g*g,_=[(g*v-d*b)/m+l,(f*b-y*v)/m+h];dk(n.edge,u,p,_),c.edge=hk(u,t,null,_),n.edge=hk(t,p,null,_),wk(e),wk(n)}else c.edge=hk(e.site,c.site)}}function Nk(t,e){var n=t.site,r=n[0],i=n[1],a=i-e;if(!a)return r;var o=t.P;if(!o)return-1/0;var s=(n=o.site)[0],c=n[1],u=c-e;if(!u)return s;var l=s-r,h=1/a-1/u,f=l/u;return h?(-f+Math.sqrt(f*f-2*h*(l*l/(-2*u)-c+u/2+i-a/2)))/h+r:(r+s)/2}function Dk(t,e){var n=t.N;if(n)return Nk(n,e);var r=t.site;return r[1]===e?r[0]:1/0}var Ok,Bk,Lk,Ik,Rk=1e-6,Fk=1e-12;function Pk(t,e,n){return(t[0]-n[0])*(e[1]-t[1])-(t[0]-e[0])*(n[1]-t[1])}function jk(t,e){return e[1]-t[1]||e[0]-t[0]}function Yk(t,e){var n,r,i,a=t.sort(jk).pop();for(Ik=[],Bk=new Array(t.length),Ok=new lk,Lk=new lk;;)if(i=bk,a&&(!i||a[1]Rk||Math.abs(i[0][1]-i[1][1])>Rk)||delete Ik[a]}(o,s,c,u),function(t,e,n,r){var i,a,o,s,c,u,l,h,f,d,p,y,g=Bk.length,m=!0;for(i=0;iRk||Math.abs(y-f)>Rk)&&(c.splice(s,0,Ik.push(fk(o,d,Math.abs(p-t)Rk?[t,Math.abs(h-t)Rk?[Math.abs(f-r)Rk?[n,Math.abs(h-n)Rk?[Math.abs(f-e)=s)return null;var c=t-i.site[0],u=e-i.site[1],l=c*c+u*u;do{i=a.cells[r=o],o=null,i.halfedges.forEach((function(n){var r=a.edges[n],s=r.left;if(s!==i.site&&s||(s=r.right)){var c=t-s[0],u=e-s[1],h=c*c+u*u;hr?(r+i)/2:Math.min(0,r)||Math.max(0,i),o>a?(a+o)/2:Math.min(0,a)||Math.max(0,o))}function eT(){var t,e,n=Xk,r=Zk,i=tT,a=Kk,o=Jk,s=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],u=250,l=Ep,h=ft("start","zoom","end"),f=500,d=0;function p(t){t.property("__zoom",Qk).on("wheel.zoom",x).on("mousedown.zoom",w).on("dblclick.zoom",k).filter(o).on("touchstart.zoom",T).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",C).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,e){return(e=Math.max(s[0],Math.min(s[1],e)))===t.k?t:new Hk(e,t.x,t.y)}function g(t,e,n){var r=e[0]-n[0]*t.k,i=e[1]-n[1]*t.k;return r===t.x&&i===t.y?t:new Hk(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function v(t,e,n){t.on("start.zoom",(function(){b(this,arguments).start()})).on("interrupt.zoom end.zoom",(function(){b(this,arguments).end()})).tween("zoom",(function(){var t=this,i=arguments,a=b(t,i),o=r.apply(t,i),s=null==n?m(o):"function"==typeof n?n.apply(t,i):n,c=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),u=t.__zoom,h="function"==typeof e?e.apply(t,i):e,f=l(u.invert(s).concat(c/u.k),h.invert(s).concat(c/h.k));return function(t){if(1===t)t=h;else{var e=f(t),n=c/e[2];t=new Hk(n,s[0]-e[0]*n,s[1]-e[1]*n)}a.zoom(null,t)}}))}function b(t,e,n){return!n&&t.__zooming||new _(t,e)}function _(t,e){this.that=t,this.args=e,this.active=0,this.extent=r.apply(t,e),this.taps=0}function x(){if(n.apply(this,arguments)){var t=b(this,arguments),e=this.__zoom,r=Math.max(s[0],Math.min(s[1],e.k*Math.pow(2,a.apply(this,arguments)))),o=On(this);if(t.wheel)t.mouse[0][0]===o[0]&&t.mouse[0][1]===o[1]||(t.mouse[1]=e.invert(t.mouse[0]=o)),clearTimeout(t.wheel);else{if(e.k===r)return;t.mouse=[o,e.invert(o)],ir(this),t.start()}Gk(),t.wheel=setTimeout(u,150),t.zoom("mouse",i(g(y(e,r),t.mouse[0],t.mouse[1]),t.extent,c))}function u(){t.wheel=null,t.end()}}function w(){if(!e&&n.apply(this,arguments)){var t=b(this,arguments,!0),r=Te(le.view).on("mousemove.zoom",u,!0).on("mouseup.zoom",l,!0),a=On(this),o=le.clientX,s=le.clientY;Se(le.view),Vk(),t.mouse=[a,this.__zoom.invert(a)],ir(this),t.start()}function u(){if(Gk(),!t.moved){var e=le.clientX-o,n=le.clientY-s;t.moved=e*e+n*n>d}t.zoom("mouse",i(g(t.that.__zoom,t.mouse[0]=On(t.that),t.mouse[1]),t.extent,c))}function l(){r.on("mousemove.zoom mouseup.zoom",null),Ae(le.view,t.moved),Gk(),t.end()}}function k(){if(n.apply(this,arguments)){var t=this.__zoom,e=On(this),a=t.invert(e),o=t.k*(le.shiftKey?.5:2),s=i(g(y(t,o),e,a),r.apply(this,arguments),c);Gk(),u>0?Te(this).transition().duration(u).call(v,s,e):Te(this).call(p.transform,s)}}function T(){if(n.apply(this,arguments)){var e,r,i,a,o=le.touches,s=o.length,c=b(this,arguments,le.changedTouches.length===s);for(Vk(),r=0;r{t.exports={graphlib:n(574),layout:n(8123),debug:n(7570),util:{time:n(1138).time,notime:n(1138).notime},version:n(8177)}},1207:(t,e,n)=>{"use strict";var r=n(8436),i=n(4079);t.exports={run:function(t){var e="greedy"===t.graph().acyclicer?i(t,function(t){return function(e){return t.edge(e).weight}}(t)):function(t){var e=[],n={},i={};return r.forEach(t.nodes(),(function a(o){r.has(i,o)||(i[o]=!0,n[o]=!0,r.forEach(t.outEdges(o),(function(t){r.has(n,t.w)?e.push(t):a(t.w)})),delete n[o])})),e}(t);r.forEach(e,(function(e){var n=t.edge(e);t.removeEdge(e),n.forwardName=e.name,n.reversed=!0,t.setEdge(e.w,e.v,n,r.uniqueId("rev"))}))},undo:function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(n.reversed){t.removeEdge(e);var r=n.forwardName;delete n.reversed,delete n.forwardName,t.setEdge(e.w,e.v,n,r)}}))}}},1133:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n,r,a,o){var s={width:0,height:0,rank:o,borderType:e},c=a[e][o-1],u=i.addDummyNode(t,"border",s,n);a[e][o]=u,t.setParent(u,r),c&&t.setEdge(c,u,{weight:1})}t.exports=function(t){r.forEach(t.children(),(function e(n){var i=t.children(n),o=t.node(n);if(i.length&&r.forEach(i,e),r.has(o,"minRank")){o.borderLeft=[],o.borderRight=[];for(var s=o.minRank,c=o.maxRank+1;s{"use strict";var r=n(8436);function i(t){r.forEach(t.nodes(),(function(e){a(t.node(e))})),r.forEach(t.edges(),(function(e){a(t.edge(e))}))}function a(t){var e=t.width;t.width=t.height,t.height=e}function o(t){t.y=-t.y}function s(t){var e=t.x;t.x=t.y,t.y=e}t.exports={adjust:function(t){var e=t.graph().rankdir.toLowerCase();"lr"!==e&&"rl"!==e||i(t)},undo:function(t){var e=t.graph().rankdir.toLowerCase();"bt"!==e&&"rl"!==e||function(t){r.forEach(t.nodes(),(function(e){o(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.forEach(n.points,o),r.has(n,"y")&&o(n)}))}(t),"lr"!==e&&"rl"!==e||(function(t){r.forEach(t.nodes(),(function(e){s(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.forEach(n.points,s),r.has(n,"x")&&s(n)}))}(t),i(t))}}},7822:t=>{function e(){var t={};t._next=t._prev=t,this._sentinel=t}function n(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function r(t,e){if("_next"!==t&&"_prev"!==t)return e}t.exports=e,e.prototype.dequeue=function(){var t=this._sentinel,e=t._prev;if(e!==t)return n(e),e},e.prototype.enqueue=function(t){var e=this._sentinel;t._prev&&t._next&&n(t),t._next=e._next,e._next._prev=t,e._next=t,t._prev=e},e.prototype.toString=function(){for(var t=[],e=this._sentinel,n=e._prev;n!==e;)t.push(JSON.stringify(n,r)),n=n._prev;return"["+t.join(", ")+"]"}},7570:(t,e,n)=>{var r=n(8436),i=n(1138),a=n(574).Graph;t.exports={debugOrdering:function(t){var e=i.buildLayerMatrix(t),n=new a({compound:!0,multigraph:!0}).setGraph({});return r.forEach(t.nodes(),(function(e){n.setNode(e,{label:e}),n.setParent(e,"layer"+t.node(e).rank)})),r.forEach(t.edges(),(function(t){n.setEdge(t.v,t.w,{},t.name)})),r.forEach(e,(function(t,e){var i="layer"+e;n.setNode(i,{rank:"same"}),r.reduce(t,(function(t,e){return n.setEdge(t,e,{style:"invis"}),e}))})),n}}},574:(t,e,n)=>{var r;try{r=n(8282)}catch(t){}r||(r=window.graphlib),t.exports=r},4079:(t,e,n)=>{var r=n(8436),i=n(574).Graph,a=n(7822);t.exports=function(t,e){if(t.nodeCount()<=1)return[];var n=function(t,e){var n=new i,o=0,s=0;r.forEach(t.nodes(),(function(t){n.setNode(t,{v:t,in:0,out:0})})),r.forEach(t.edges(),(function(t){var r=n.edge(t.v,t.w)||0,i=e(t),a=r+i;n.setEdge(t.v,t.w,a),s=Math.max(s,n.node(t.v).out+=i),o=Math.max(o,n.node(t.w).in+=i)}));var u=r.range(s+o+3).map((function(){return new a})),l=o+1;return r.forEach(n.nodes(),(function(t){c(u,l,n.node(t))})),{graph:n,buckets:u,zeroIdx:l}}(t,e||o),u=function(t,e,n){for(var r,i=[],a=e[e.length-1],o=e[0];t.nodeCount();){for(;r=o.dequeue();)s(t,e,n,r);for(;r=a.dequeue();)s(t,e,n,r);if(t.nodeCount())for(var c=e.length-2;c>0;--c)if(r=e[c].dequeue()){i=i.concat(s(t,e,n,r,!0));break}}return i}(n.graph,n.buckets,n.zeroIdx);return r.flatten(r.map(u,(function(e){return t.outEdges(e.v,e.w)})),!0)};var o=r.constant(1);function s(t,e,n,i,a){var o=a?[]:void 0;return r.forEach(t.inEdges(i.v),(function(r){var i=t.edge(r),s=t.node(r.v);a&&o.push({v:r.v,w:r.w}),s.out-=i,c(e,n,s)})),r.forEach(t.outEdges(i.v),(function(r){var i=t.edge(r),a=r.w,o=t.node(a);o.in-=i,c(e,n,o)})),t.removeNode(i.v),o}function c(t,e,n){n.out?n.in?t[n.out-n.in+e].enqueue(n):t[t.length-1].enqueue(n):t[0].enqueue(n)}},8123:(t,e,n)=>{"use strict";var r=n(8436),i=n(1207),a=n(5995),o=n(8093),s=n(1138).normalizeRanks,c=n(4219),u=n(1138).removeEmptyRanks,l=n(2981),h=n(1133),f=n(3258),d=n(3408),p=n(7873),y=n(1138),g=n(574).Graph;t.exports=function(t,e){var n=e&&e.debugTiming?y.time:y.notime;n("layout",(function(){var e=n(" buildLayoutGraph",(function(){return function(t){var e=new g({multigraph:!0,compound:!0}),n=C(t.graph());return e.setGraph(r.merge({},v,E(n,m),r.pick(n,b))),r.forEach(t.nodes(),(function(n){var i=C(t.node(n));e.setNode(n,r.defaults(E(i,_),x)),e.setParent(n,t.parent(n))})),r.forEach(t.edges(),(function(n){var i=C(t.edge(n));e.setEdge(n,r.merge({},k,E(i,w),r.pick(i,T)))})),e}(t)}));n(" runLayout",(function(){!function(t,e){e(" makeSpaceForEdgeLabels",(function(){!function(t){var e=t.graph();e.ranksep/=2,r.forEach(t.edges(),(function(n){var r=t.edge(n);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===e.rankdir||"BT"===e.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)}))}(t)})),e(" removeSelfEdges",(function(){!function(t){r.forEach(t.edges(),(function(e){if(e.v===e.w){var n=t.node(e.v);n.selfEdges||(n.selfEdges=[]),n.selfEdges.push({e:e,label:t.edge(e)}),t.removeEdge(e)}}))}(t)})),e(" acyclic",(function(){i.run(t)})),e(" nestingGraph.run",(function(){l.run(t)})),e(" rank",(function(){o(y.asNonCompoundGraph(t))})),e(" injectEdgeLabelProxies",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(n.width&&n.height){var r=t.node(e.v),i={rank:(t.node(e.w).rank-r.rank)/2+r.rank,e:e};y.addDummyNode(t,"edge-proxy",i,"_ep")}}))}(t)})),e(" removeEmptyRanks",(function(){u(t)})),e(" nestingGraph.cleanup",(function(){l.cleanup(t)})),e(" normalizeRanks",(function(){s(t)})),e(" assignRankMinMax",(function(){!function(t){var e=0;r.forEach(t.nodes(),(function(n){var i=t.node(n);i.borderTop&&(i.minRank=t.node(i.borderTop).rank,i.maxRank=t.node(i.borderBottom).rank,e=r.max(e,i.maxRank))})),t.graph().maxRank=e}(t)})),e(" removeEdgeLabelProxies",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);"edge-proxy"===n.dummy&&(t.edge(n.e).labelRank=n.rank,t.removeNode(e))}))}(t)})),e(" normalize.run",(function(){a.run(t)})),e(" parentDummyChains",(function(){c(t)})),e(" addBorderSegments",(function(){h(t)})),e(" order",(function(){d(t)})),e(" insertSelfEdges",(function(){!function(t){var e=y.buildLayerMatrix(t);r.forEach(e,(function(e){var n=0;r.forEach(e,(function(e,i){var a=t.node(e);a.order=i+n,r.forEach(a.selfEdges,(function(e){y.addDummyNode(t,"selfedge",{width:e.label.width,height:e.label.height,rank:a.rank,order:i+ ++n,e:e.e,label:e.label},"_se")})),delete a.selfEdges}))}))}(t)})),e(" adjustCoordinateSystem",(function(){f.adjust(t)})),e(" position",(function(){p(t)})),e(" positionSelfEdges",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);if("selfedge"===n.dummy){var r=t.node(n.e.v),i=r.x+r.width/2,a=r.y,o=n.x-i,s=r.height/2;t.setEdge(n.e,n.label),t.removeNode(e),n.label.points=[{x:i+2*o/3,y:a-s},{x:i+5*o/6,y:a-s},{x:i+o,y:a},{x:i+5*o/6,y:a+s},{x:i+2*o/3,y:a+s}],n.label.x=n.x,n.label.y=n.y}}))}(t)})),e(" removeBorderNodes",(function(){!function(t){r.forEach(t.nodes(),(function(e){if(t.children(e).length){var n=t.node(e),i=t.node(n.borderTop),a=t.node(n.borderBottom),o=t.node(r.last(n.borderLeft)),s=t.node(r.last(n.borderRight));n.width=Math.abs(s.x-o.x),n.height=Math.abs(a.y-i.y),n.x=o.x+n.width/2,n.y=i.y+n.height/2}})),r.forEach(t.nodes(),(function(e){"border"===t.node(e).dummy&&t.removeNode(e)}))}(t)})),e(" normalize.undo",(function(){a.undo(t)})),e(" fixupEdgeLabelCoords",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(r.has(n,"x"))switch("l"!==n.labelpos&&"r"!==n.labelpos||(n.width-=n.labeloffset),n.labelpos){case"l":n.x-=n.width/2+n.labeloffset;break;case"r":n.x+=n.width/2+n.labeloffset}}))}(t)})),e(" undoCoordinateSystem",(function(){f.undo(t)})),e(" translateGraph",(function(){!function(t){var e=Number.POSITIVE_INFINITY,n=0,i=Number.POSITIVE_INFINITY,a=0,o=t.graph(),s=o.marginx||0,c=o.marginy||0;function u(t){var r=t.x,o=t.y,s=t.width,c=t.height;e=Math.min(e,r-s/2),n=Math.max(n,r+s/2),i=Math.min(i,o-c/2),a=Math.max(a,o+c/2)}r.forEach(t.nodes(),(function(e){u(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.has(n,"x")&&u(n)})),e-=s,i-=c,r.forEach(t.nodes(),(function(n){var r=t.node(n);r.x-=e,r.y-=i})),r.forEach(t.edges(),(function(n){var a=t.edge(n);r.forEach(a.points,(function(t){t.x-=e,t.y-=i})),r.has(a,"x")&&(a.x-=e),r.has(a,"y")&&(a.y-=i)})),o.width=n-e+s,o.height=a-i+c}(t)})),e(" assignNodeIntersects",(function(){!function(t){r.forEach(t.edges(),(function(e){var n,r,i=t.edge(e),a=t.node(e.v),o=t.node(e.w);i.points?(n=i.points[0],r=i.points[i.points.length-1]):(i.points=[],n=o,r=a),i.points.unshift(y.intersectRect(a,n)),i.points.push(y.intersectRect(o,r))}))}(t)})),e(" reversePoints",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);n.reversed&&n.points.reverse()}))}(t)})),e(" acyclic.undo",(function(){i.undo(t)}))}(e,n)})),n(" updateInputGraph",(function(){!function(t,e){r.forEach(t.nodes(),(function(n){var r=t.node(n),i=e.node(n);r&&(r.x=i.x,r.y=i.y,e.children(n).length&&(r.width=i.width,r.height=i.height))})),r.forEach(t.edges(),(function(n){var i=t.edge(n),a=e.edge(n);i.points=a.points,r.has(a,"x")&&(i.x=a.x,i.y=a.y)})),t.graph().width=e.graph().width,t.graph().height=e.graph().height}(t,e)}))}))};var m=["nodesep","edgesep","ranksep","marginx","marginy"],v={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},b=["acyclicer","ranker","rankdir","align"],_=["width","height"],x={width:0,height:0},w=["minlen","weight","width","height","labeloffset"],k={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},T=["labelpos"];function E(t,e){return r.mapValues(r.pick(t,e),Number)}function C(t){var e={};return r.forEach(t,(function(t,n){e[n.toLowerCase()]=t})),e}},8436:(t,e,n)=>{var r;try{r={cloneDeep:n(361),constant:n(5703),defaults:n(1747),each:n(6073),filter:n(3105),find:n(3311),flatten:n(5564),forEach:n(4486),forIn:n(2620),has:n(8721),isUndefined:n(2353),last:n(928),map:n(5161),mapValues:n(6604),max:n(6162),merge:n(3857),min:n(3632),minBy:n(2762),now:n(7771),pick:n(9722),range:n(6026),reduce:n(4061),sortBy:n(9734),uniqueId:n(3955),values:n(2628),zipObject:n(7287)}}catch(t){}r||(r=window._),t.exports=r},2981:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n,o,s,c,u){var l=t.children(u);if(l.length){var h=i.addBorderNode(t,"_bt"),f=i.addBorderNode(t,"_bb"),d=t.node(u);t.setParent(h,u),d.borderTop=h,t.setParent(f,u),d.borderBottom=f,r.forEach(l,(function(r){a(t,e,n,o,s,c,r);var i=t.node(r),l=i.borderTop?i.borderTop:r,d=i.borderBottom?i.borderBottom:r,p=i.borderTop?o:2*o,y=l!==d?1:s-c[u]+1;t.setEdge(h,l,{weight:p,minlen:y,nestingEdge:!0}),t.setEdge(d,f,{weight:p,minlen:y,nestingEdge:!0})})),t.parent(u)||t.setEdge(e,h,{weight:0,minlen:s+c[u]})}else u!==e&&t.setEdge(e,u,{weight:0,minlen:n})}t.exports={run:function(t){var e=i.addDummyNode(t,"root",{},"_root"),n=function(t){var e={};function n(i,a){var o=t.children(i);o&&o.length&&r.forEach(o,(function(t){n(t,a+1)})),e[i]=a}return r.forEach(t.children(),(function(t){n(t,1)})),e}(t),o=r.max(r.values(n))-1,s=2*o+1;t.graph().nestingRoot=e,r.forEach(t.edges(),(function(e){t.edge(e).minlen*=s}));var c=function(t){return r.reduce(t.edges(),(function(e,n){return e+t.edge(n).weight}),0)}(t)+1;r.forEach(t.children(),(function(r){a(t,e,s,c,o,n,r)})),t.graph().nodeRankFactor=s},cleanup:function(t){var e=t.graph();t.removeNode(e.nestingRoot),delete e.nestingRoot,r.forEach(t.edges(),(function(e){t.edge(e).nestingEdge&&t.removeEdge(e)}))}}},5995:(t,e,n)=>{"use strict";var r=n(8436),i=n(1138);t.exports={run:function(t){t.graph().dummyChains=[],r.forEach(t.edges(),(function(e){!function(t,e){var n,r,a,o=e.v,s=t.node(o).rank,c=e.w,u=t.node(c).rank,l=e.name,h=t.edge(e),f=h.labelRank;if(u!==s+1){for(t.removeEdge(e),a=0,++s;s{var r=n(8436);t.exports=function(t,e,n){var i,a={};r.forEach(n,(function(n){for(var r,o,s=t.parent(n);s;){if((r=t.parent(s))?(o=a[r],a[r]=s):(o=i,i=s),o&&o!==s)return void e.setEdge(o,s);s=r}}))}},5439:(t,e,n)=>{var r=n(8436);t.exports=function(t,e){return r.map(e,(function(e){var n=t.inEdges(e);if(n.length){var i=r.reduce(n,(function(e,n){var r=t.edge(n),i=t.node(n.v);return{sum:e.sum+r.weight*i.order,weight:e.weight+r.weight}}),{sum:0,weight:0});return{v:e,barycenter:i.sum/i.weight,weight:i.weight}}return{v:e}}))}},3128:(t,e,n)=>{var r=n(8436),i=n(574).Graph;t.exports=function(t,e,n){var a=function(t){for(var e;t.hasNode(e=r.uniqueId("_root")););return e}(t),o=new i({compound:!0}).setGraph({root:a}).setDefaultNodeLabel((function(e){return t.node(e)}));return r.forEach(t.nodes(),(function(i){var s=t.node(i),c=t.parent(i);(s.rank===e||s.minRank<=e&&e<=s.maxRank)&&(o.setNode(i),o.setParent(i,c||a),r.forEach(t[n](i),(function(e){var n=e.v===i?e.w:e.v,a=o.edge(n,i),s=r.isUndefined(a)?0:a.weight;o.setEdge(n,i,{weight:t.edge(e).weight+s})})),r.has(s,"minRank")&&o.setNode(i,{borderLeft:s.borderLeft[e],borderRight:s.borderRight[e]}))})),o}},6630:(t,e,n)=>{"use strict";var r=n(8436);function i(t,e,n){for(var i=r.zipObject(n,r.map(n,(function(t,e){return e}))),a=r.flatten(r.map(e,(function(e){return r.sortBy(r.map(t.outEdges(e),(function(e){return{pos:i[e.w],weight:t.edge(e).weight}})),"pos")})),!0),o=1;o0;)e%2&&(n+=c[e+1]),c[e=e-1>>1]+=t.weight;u+=t.weight*n}))),u}t.exports=function(t,e){for(var n=0,r=1;r{"use strict";var r=n(8436),i=n(2588),a=n(6630),o=n(1026),s=n(3128),c=n(5093),u=n(574).Graph,l=n(1138);function h(t,e,n){return r.map(e,(function(e){return s(t,e,n)}))}function f(t,e){var n=new u;r.forEach(t,(function(t){var i=t.graph().root,a=o(t,i,n,e);r.forEach(a.vs,(function(e,n){t.node(e).order=n})),c(t,n,a.vs)}))}function d(t,e){r.forEach(e,(function(e){r.forEach(e,(function(e,n){t.node(e).order=n}))}))}t.exports=function(t){var e=l.maxRank(t),n=h(t,r.range(1,e+1),"inEdges"),o=h(t,r.range(e-1,-1,-1),"outEdges"),s=i(t);d(t,s);for(var c,u=Number.POSITIVE_INFINITY,p=0,y=0;y<4;++p,++y){f(p%2?n:o,p%4>=2),s=l.buildLayerMatrix(t);var g=a(t,s);g{"use strict";var r=n(8436);t.exports=function(t){var e={},n=r.filter(t.nodes(),(function(e){return!t.children(e).length})),i=r.max(r.map(n,(function(e){return t.node(e).rank}))),a=r.map(r.range(i+1),(function(){return[]})),o=r.sortBy(n,(function(e){return t.node(e).rank}));return r.forEach(o,(function n(i){if(!r.has(e,i)){e[i]=!0;var o=t.node(i);a[o.rank].push(i),r.forEach(t.successors(i),n)}})),a}},9567:(t,e,n)=>{"use strict";var r=n(8436);t.exports=function(t,e){var n={};return r.forEach(t,(function(t,e){var i=n[t.v]={indegree:0,in:[],out:[],vs:[t.v],i:e};r.isUndefined(t.barycenter)||(i.barycenter=t.barycenter,i.weight=t.weight)})),r.forEach(e.edges(),(function(t){var e=n[t.v],i=n[t.w];r.isUndefined(e)||r.isUndefined(i)||(i.indegree++,e.out.push(n[t.w]))})),function(t){var e=[];function n(t){return function(e){var n,i,a,o;e.merged||(r.isUndefined(e.barycenter)||r.isUndefined(t.barycenter)||e.barycenter>=t.barycenter)&&(i=e,a=0,o=0,(n=t).weight&&(a+=n.barycenter*n.weight,o+=n.weight),i.weight&&(a+=i.barycenter*i.weight,o+=i.weight),n.vs=i.vs.concat(n.vs),n.barycenter=a/o,n.weight=o,n.i=Math.min(i.i,n.i),i.merged=!0)}}function i(e){return function(n){n.in.push(e),0==--n.indegree&&t.push(n)}}for(;t.length;){var a=t.pop();e.push(a),r.forEach(a.in.reverse(),n(a)),r.forEach(a.out,i(a))}return r.map(r.filter(e,(function(t){return!t.merged})),(function(t){return r.pick(t,["vs","i","barycenter","weight"])}))}(r.filter(n,(function(t){return!t.indegree})))}},1026:(t,e,n)=>{var r=n(8436),i=n(5439),a=n(9567),o=n(7304);t.exports=function t(e,n,s,c){var u=e.children(n),l=e.node(n),h=l?l.borderLeft:void 0,f=l?l.borderRight:void 0,d={};h&&(u=r.filter(u,(function(t){return t!==h&&t!==f})));var p=i(e,u);r.forEach(p,(function(n){if(e.children(n.v).length){var i=t(e,n.v,s,c);d[n.v]=i,r.has(i,"barycenter")&&(a=n,o=i,r.isUndefined(a.barycenter)?(a.barycenter=o.barycenter,a.weight=o.weight):(a.barycenter=(a.barycenter*a.weight+o.barycenter*o.weight)/(a.weight+o.weight),a.weight+=o.weight))}var a,o}));var y=a(p,s);!function(t,e){r.forEach(t,(function(t){t.vs=r.flatten(t.vs.map((function(t){return e[t]?e[t].vs:t})),!0)}))}(y,d);var g=o(y,c);if(h&&(g.vs=r.flatten([h,g.vs,f],!0),e.predecessors(h).length)){var m=e.node(e.predecessors(h)[0]),v=e.node(e.predecessors(f)[0]);r.has(g,"barycenter")||(g.barycenter=0,g.weight=0),g.barycenter=(g.barycenter*g.weight+m.order+v.order)/(g.weight+2),g.weight+=2}return g}},7304:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n){for(var i;e.length&&(i=r.last(e)).i<=n;)e.pop(),t.push(i.vs),n++;return n}t.exports=function(t,e){var n,o=i.partition(t,(function(t){return r.has(t,"barycenter")})),s=o.lhs,c=r.sortBy(o.rhs,(function(t){return-t.i})),u=[],l=0,h=0,f=0;s.sort((n=!!e,function(t,e){return t.barycentere.barycenter?1:n?e.i-t.i:t.i-e.i})),f=a(u,c,f),r.forEach(s,(function(t){f+=t.vs.length,u.push(t.vs),l+=t.barycenter*t.weight,h+=t.weight,f=a(u,c,f)}));var d={vs:r.flatten(u,!0)};return h&&(d.barycenter=l/h,d.weight=h),d}},4219:(t,e,n)=>{var r=n(8436);t.exports=function(t){var e=function(t){var e={},n=0;return r.forEach(t.children(),(function i(a){var o=n;r.forEach(t.children(a),i),e[a]={low:o,lim:n++}})),e}(t);r.forEach(t.graph().dummyChains,(function(n){for(var r=t.node(n),i=r.edgeObj,a=function(t,e,n,r){var i,a,o=[],s=[],c=Math.min(e[n].low,e[r].low),u=Math.max(e[n].lim,e[r].lim);i=n;do{i=t.parent(i),o.push(i)}while(i&&(e[i].low>c||u>e[i].lim));for(a=i,i=r;(i=t.parent(i))!==a;)s.push(i);return{path:o.concat(s.reverse()),lca:a}}(t,e,i.v,i.w),o=a.path,s=a.lca,c=0,u=o[c],l=!0;n!==i.w;){if(r=t.node(n),l){for(;(u=o[c])!==s&&t.node(u).maxRank{"use strict";var r=n(8436),i=n(574).Graph,a=n(1138);function o(t,e){var n={};return r.reduce(e,(function(e,i){var a=0,o=0,s=e.length,u=r.last(i);return r.forEach(i,(function(e,l){var h=function(t,e){if(t.node(e).dummy)return r.find(t.predecessors(e),(function(e){return t.node(e).dummy}))}(t,e),f=h?t.node(h).order:s;(h||e===u)&&(r.forEach(i.slice(o,l+1),(function(e){r.forEach(t.predecessors(e),(function(r){var i=t.node(r),o=i.order;!(os)&&c(n,e,u)}))}))}return r.reduce(e,(function(e,n){var a,o=-1,s=0;return r.forEach(n,(function(r,c){if("border"===t.node(r).dummy){var u=t.predecessors(r);u.length&&(a=t.node(u[0]).order,i(n,s,c,o,a),s=c,o=a)}i(n,s,n.length,a,e.length)})),n})),n}function c(t,e,n){if(e>n){var r=e;e=n,n=r}var i=t[e];i||(t[e]=i={}),i[n]=!0}function u(t,e,n){if(e>n){var i=e;e=n,n=i}return r.has(t[e],n)}function l(t,e,n,i){var a={},o={},s={};return r.forEach(e,(function(t){r.forEach(t,(function(t,e){a[t]=t,o[t]=t,s[t]=e}))})),r.forEach(e,(function(t){var e=-1;r.forEach(t,(function(t){var c=i(t);if(c.length)for(var l=((c=r.sortBy(c,(function(t){return s[t]}))).length-1)/2,h=Math.floor(l),f=Math.ceil(l);h<=f;++h){var d=c[h];o[t]===t&&e{"use strict";var r=n(8436),i=n(1138),a=n(3573).positionX;t.exports=function(t){(function(t){var e=i.buildLayerMatrix(t),n=t.graph().ranksep,a=0;r.forEach(e,(function(e){var i=r.max(r.map(e,(function(e){return t.node(e).height})));r.forEach(e,(function(e){t.node(e).y=a+i/2})),a+=i+n}))})(t=i.asNonCompoundGraph(t)),r.forEach(a(t),(function(e,n){t.node(n).x=e}))}},300:(t,e,n)=>{"use strict";var r=n(8436),i=n(574).Graph,a=n(6681).slack;function o(t,e){return r.forEach(t.nodes(),(function n(i){r.forEach(e.nodeEdges(i),(function(r){var o=r.v,s=i===o?r.w:o;t.hasNode(s)||a(e,r)||(t.setNode(s,{}),t.setEdge(i,s,{}),n(s))}))})),t.nodeCount()}function s(t,e){return r.minBy(e.edges(),(function(n){if(t.hasNode(n.v)!==t.hasNode(n.w))return a(e,n)}))}function c(t,e,n){r.forEach(t.nodes(),(function(t){e.node(t).rank+=n}))}t.exports=function(t){var e,n,r=new i({directed:!1}),u=t.nodes()[0],l=t.nodeCount();for(r.setNode(u,{});o(r,t){"use strict";var r=n(6681).longestPath,i=n(300),a=n(2472);t.exports=function(t){switch(t.graph().ranker){case"network-simplex":default:!function(t){a(t)}(t);break;case"tight-tree":!function(t){r(t),i(t)}(t);break;case"longest-path":o(t)}};var o=r},2472:(t,e,n)=>{"use strict";var r=n(8436),i=n(300),a=n(6681).slack,o=n(6681).longestPath,s=n(574).alg.preorder,c=n(574).alg.postorder,u=n(1138).simplify;function l(t){t=u(t),o(t);var e,n=i(t);for(d(n),h(n,t);e=y(n);)m(n,t,e,g(n,t,e))}function h(t,e){var n=c(t,t.nodes());n=n.slice(0,n.length-1),r.forEach(n,(function(n){!function(t,e,n){var r=t.node(n).parent;t.edge(n,r).cutvalue=f(t,e,n)}(t,e,n)}))}function f(t,e,n){var i=t.node(n).parent,a=!0,o=e.edge(n,i),s=0;return o||(a=!1,o=e.edge(i,n)),s=o.weight,r.forEach(e.nodeEdges(n),(function(r){var o,c,u=r.v===n,l=u?r.w:r.v;if(l!==i){var h=u===a,f=e.edge(r).weight;if(s+=h?f:-f,o=n,c=l,t.hasEdge(o,c)){var d=t.edge(n,l).cutvalue;s+=h?-d:d}}})),s}function d(t,e){arguments.length<2&&(e=t.nodes()[0]),p(t,{},1,e)}function p(t,e,n,i,a){var o=n,s=t.node(i);return e[i]=!0,r.forEach(t.neighbors(i),(function(a){r.has(e,a)||(n=p(t,e,n,a,i))})),s.low=o,s.lim=n++,a?s.parent=a:delete s.parent,n}function y(t){return r.find(t.edges(),(function(e){return t.edge(e).cutvalue<0}))}function g(t,e,n){var i=n.v,o=n.w;e.hasEdge(i,o)||(i=n.w,o=n.v);var s=t.node(i),c=t.node(o),u=s,l=!1;s.lim>c.lim&&(u=c,l=!0);var h=r.filter(e.edges(),(function(e){return l===v(0,t.node(e.v),u)&&l!==v(0,t.node(e.w),u)}));return r.minBy(h,(function(t){return a(e,t)}))}function m(t,e,n,i){var a=n.v,o=n.w;t.removeEdge(a,o),t.setEdge(i.v,i.w,{}),d(t),h(t,e),function(t,e){var n=r.find(t.nodes(),(function(t){return!e.node(t).parent})),i=s(t,n);i=i.slice(1),r.forEach(i,(function(n){var r=t.node(n).parent,i=e.edge(n,r),a=!1;i||(i=e.edge(r,n),a=!0),e.node(n).rank=e.node(r).rank+(a?i.minlen:-i.minlen)}))}(t,e)}function v(t,e,n){return n.low<=e.lim&&e.lim<=n.lim}t.exports=l,l.initLowLimValues=d,l.initCutValues=h,l.calcCutValue=f,l.leaveEdge=y,l.enterEdge=g,l.exchangeEdges=m},6681:(t,e,n)=>{"use strict";var r=n(8436);t.exports={longestPath:function(t){var e={};r.forEach(t.sources(),(function n(i){var a=t.node(i);if(r.has(e,i))return a.rank;e[i]=!0;var o=r.min(r.map(t.outEdges(i),(function(e){return n(e.w)-t.edge(e).minlen})));return o!==Number.POSITIVE_INFINITY&&null!=o||(o=0),a.rank=o}))},slack:function(t,e){return t.node(e.w).rank-t.node(e.v).rank-t.edge(e).minlen}}},1138:(t,e,n)=>{"use strict";var r=n(8436),i=n(574).Graph;function a(t,e,n,i){var a;do{a=r.uniqueId(i)}while(t.hasNode(a));return n.dummy=e,t.setNode(a,n),a}function o(t){return r.max(r.map(t.nodes(),(function(e){var n=t.node(e).rank;if(!r.isUndefined(n))return n})))}t.exports={addDummyNode:a,simplify:function(t){var e=(new i).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){var r=e.edge(n.v,n.w)||{weight:0,minlen:1},i=t.edge(n);e.setEdge(n.v,n.w,{weight:r.weight+i.weight,minlen:Math.max(r.minlen,i.minlen)})})),e},asNonCompoundGraph:function(t){var e=new i({multigraph:t.isMultigraph()}).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){t.children(n).length||e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){e.setEdge(n,t.edge(n))})),e},successorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.outEdges(e),(function(e){n[e.w]=(n[e.w]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},predecessorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.inEdges(e),(function(e){n[e.v]=(n[e.v]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},intersectRect:function(t,e){var n,r,i=t.x,a=t.y,o=e.x-i,s=e.y-a,c=t.width/2,u=t.height/2;if(!o&&!s)throw new Error("Not possible to find intersection inside of the rectangle");return Math.abs(s)*c>Math.abs(o)*u?(s<0&&(u=-u),n=u*o/s,r=u):(o<0&&(c=-c),n=c,r=c*s/o),{x:i+n,y:a+r}},buildLayerMatrix:function(t){var e=r.map(r.range(o(t)+1),(function(){return[]}));return r.forEach(t.nodes(),(function(n){var i=t.node(n),a=i.rank;r.isUndefined(a)||(e[a][i.order]=n)})),e},normalizeRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank})));r.forEach(t.nodes(),(function(n){var i=t.node(n);r.has(i,"rank")&&(i.rank-=e)}))},removeEmptyRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank}))),n=[];r.forEach(t.nodes(),(function(r){var i=t.node(r).rank-e;n[i]||(n[i]=[]),n[i].push(r)}));var i=0,a=t.graph().nodeRankFactor;r.forEach(n,(function(e,n){r.isUndefined(e)&&n%a!=0?--i:i&&r.forEach(e,(function(e){t.node(e).rank+=i}))}))},addBorderNode:function(t,e,n,r){var i={width:0,height:0};return arguments.length>=4&&(i.rank=n,i.order=r),a(t,"border",i,e)},maxRank:o,partition:function(t,e){var n={lhs:[],rhs:[]};return r.forEach(t,(function(t){e(t)?n.lhs.push(t):n.rhs.push(t)})),n},time:function(t,e){var n=r.now();try{return e()}finally{console.log(t+" time: "+(r.now()-n)+"ms")}},notime:function(t,e){return e()}}},8177:t=>{t.exports="0.8.5"},7856:function(t){t.exports=function(){"use strict";var t=Object.hasOwnProperty,e=Object.setPrototypeOf,n=Object.isFrozen,r=Object.getPrototypeOf,i=Object.getOwnPropertyDescriptor,a=Object.freeze,o=Object.seal,s=Object.create,c="undefined"!=typeof Reflect&&Reflect,u=c.apply,l=c.construct;u||(u=function(t,e,n){return t.apply(e,n)}),a||(a=function(t){return t}),o||(o=function(t){return t}),l||(l=function(t,e){return new(Function.prototype.bind.apply(t,[null].concat(function(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e1?n-1:0),i=1;i/gm),j=o(/^data-[\-\w.\u00B7-\uFFFF]/),Y=o(/^aria-[\-\w]+$/),z=o(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),U=o(/^(?:\w+script|data):/i),q=o(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),H="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};function $(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:W(),n=function(e){return t(e)};if(n.version="2.3.5",n.removed=[],!e||!e.document||9!==e.document.nodeType)return n.isSupported=!1,n;var r=e.document,i=e.document,o=e.DocumentFragment,s=e.HTMLTemplateElement,c=e.Node,u=e.Element,l=e.NodeFilter,h=e.NamedNodeMap,w=void 0===h?e.NamedNodeMap||e.MozNamedAttrMap:h,G=e.HTMLFormElement,X=e.DOMParser,Z=e.trustedTypes,Q=u.prototype,K=E(Q,"cloneNode"),J=E(Q,"nextSibling"),tt=E(Q,"childNodes"),et=E(Q,"parentNode");if("function"==typeof s){var nt=i.createElement("template");nt.content&&nt.content.ownerDocument&&(i=nt.content.ownerDocument)}var rt=V(Z,r),it=rt?rt.createHTML(""):"",at=i,ot=at.implementation,st=at.createNodeIterator,ct=at.createDocumentFragment,ut=at.getElementsByTagName,lt=r.importNode,ht={};try{ht=T(i).documentMode?i.documentMode:{}}catch(t){}var ft={};n.isSupported="function"==typeof et&&ot&&void 0!==ot.createHTMLDocument&&9!==ht;var dt=F,pt=P,yt=j,gt=Y,mt=U,vt=q,bt=z,_t=null,xt=k({},[].concat($(C),$(S),$(A),$(N),$(O))),wt=null,kt=k({},[].concat($(B),$(L),$(I),$(R))),Tt=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Et=null,Ct=null,St=!0,At=!0,Mt=!1,Nt=!1,Dt=!1,Ot=!1,Bt=!1,Lt=!1,It=!1,Rt=!1,Ft=!0,Pt=!0,jt=!1,Yt={},zt=null,Ut=k({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),qt=null,Ht=k({},["audio","video","img","source","image","track"]),$t=null,Wt=k({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Vt="http://www.w3.org/1998/Math/MathML",Gt="http://www.w3.org/2000/svg",Xt="http://www.w3.org/1999/xhtml",Zt=Xt,Qt=!1,Kt=void 0,Jt=["application/xhtml+xml","text/html"],te="text/html",ee=void 0,ne=null,re=i.createElement("form"),ie=function(t){return t instanceof RegExp||t instanceof Function},ae=function(t){ne&&ne===t||(t&&"object"===(void 0===t?"undefined":H(t))||(t={}),t=T(t),_t="ALLOWED_TAGS"in t?k({},t.ALLOWED_TAGS):xt,wt="ALLOWED_ATTR"in t?k({},t.ALLOWED_ATTR):kt,$t="ADD_URI_SAFE_ATTR"in t?k(T(Wt),t.ADD_URI_SAFE_ATTR):Wt,qt="ADD_DATA_URI_TAGS"in t?k(T(Ht),t.ADD_DATA_URI_TAGS):Ht,zt="FORBID_CONTENTS"in t?k({},t.FORBID_CONTENTS):Ut,Et="FORBID_TAGS"in t?k({},t.FORBID_TAGS):{},Ct="FORBID_ATTR"in t?k({},t.FORBID_ATTR):{},Yt="USE_PROFILES"in t&&t.USE_PROFILES,St=!1!==t.ALLOW_ARIA_ATTR,At=!1!==t.ALLOW_DATA_ATTR,Mt=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Nt=t.SAFE_FOR_TEMPLATES||!1,Dt=t.WHOLE_DOCUMENT||!1,Lt=t.RETURN_DOM||!1,It=t.RETURN_DOM_FRAGMENT||!1,Rt=t.RETURN_TRUSTED_TYPE||!1,Bt=t.FORCE_BODY||!1,Ft=!1!==t.SANITIZE_DOM,Pt=!1!==t.KEEP_CONTENT,jt=t.IN_PLACE||!1,bt=t.ALLOWED_URI_REGEXP||bt,Zt=t.NAMESPACE||Xt,t.CUSTOM_ELEMENT_HANDLING&&ie(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Tt.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&ie(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Tt.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Tt.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Kt=Kt=-1===Jt.indexOf(t.PARSER_MEDIA_TYPE)?te:t.PARSER_MEDIA_TYPE,ee="application/xhtml+xml"===Kt?function(t){return t}:y,Nt&&(At=!1),It&&(Lt=!0),Yt&&(_t=k({},[].concat($(O))),wt=[],!0===Yt.html&&(k(_t,C),k(wt,B)),!0===Yt.svg&&(k(_t,S),k(wt,L),k(wt,R)),!0===Yt.svgFilters&&(k(_t,A),k(wt,L),k(wt,R)),!0===Yt.mathMl&&(k(_t,N),k(wt,I),k(wt,R))),t.ADD_TAGS&&(_t===xt&&(_t=T(_t)),k(_t,t.ADD_TAGS)),t.ADD_ATTR&&(wt===kt&&(wt=T(wt)),k(wt,t.ADD_ATTR)),t.ADD_URI_SAFE_ATTR&&k($t,t.ADD_URI_SAFE_ATTR),t.FORBID_CONTENTS&&(zt===Ut&&(zt=T(zt)),k(zt,t.FORBID_CONTENTS)),Pt&&(_t["#text"]=!0),Dt&&k(_t,["html","head","body"]),_t.table&&(k(_t,["tbody"]),delete Et.tbody),a&&a(t),ne=t)},oe=k({},["mi","mo","mn","ms","mtext"]),se=k({},["foreignobject","desc","title","annotation-xml"]),ce=k({},S);k(ce,A),k(ce,M);var ue=k({},N);k(ue,D);var le=function(t){var e=et(t);e&&e.tagName||(e={namespaceURI:Xt,tagName:"template"});var n=y(t.tagName),r=y(e.tagName);if(t.namespaceURI===Gt)return e.namespaceURI===Xt?"svg"===n:e.namespaceURI===Vt?"svg"===n&&("annotation-xml"===r||oe[r]):Boolean(ce[n]);if(t.namespaceURI===Vt)return e.namespaceURI===Xt?"math"===n:e.namespaceURI===Gt?"math"===n&&se[r]:Boolean(ue[n]);if(t.namespaceURI===Xt){if(e.namespaceURI===Gt&&!se[r])return!1;if(e.namespaceURI===Vt&&!oe[r])return!1;var i=k({},["title","style","font","a","script"]);return!ue[n]&&(i[n]||!ce[n])}return!1},he=function(t){p(n.removed,{element:t});try{t.parentNode.removeChild(t)}catch(e){try{t.outerHTML=it}catch(e){t.remove()}}},fe=function(t,e){try{p(n.removed,{attribute:e.getAttributeNode(t),from:e})}catch(t){p(n.removed,{attribute:null,from:e})}if(e.removeAttribute(t),"is"===t&&!wt[t])if(Lt||It)try{he(e)}catch(t){}else try{e.setAttribute(t,"")}catch(t){}},de=function(t){var e=void 0,n=void 0;if(Bt)t=""+t;else{var r=g(t,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===Kt&&(t=''+t+"");var a=rt?rt.createHTML(t):t;if(Zt===Xt)try{e=(new X).parseFromString(a,Kt)}catch(t){}if(!e||!e.documentElement){e=ot.createDocument(Zt,"template",null);try{e.documentElement.innerHTML=Qt?"":a}catch(t){}}var o=e.body||e.documentElement;return t&&n&&o.insertBefore(i.createTextNode(n),o.childNodes[0]||null),Zt===Xt?ut.call(e,Dt?"html":"body")[0]:Dt?e.documentElement:o},pe=function(t){return st.call(t.ownerDocument||t,t,l.SHOW_ELEMENT|l.SHOW_COMMENT|l.SHOW_TEXT,null,!1)},ye=function(t){return t instanceof G&&("string"!=typeof t.nodeName||"string"!=typeof t.textContent||"function"!=typeof t.removeChild||!(t.attributes instanceof w)||"function"!=typeof t.removeAttribute||"function"!=typeof t.setAttribute||"string"!=typeof t.namespaceURI||"function"!=typeof t.insertBefore)},ge=function(t){return"object"===(void 0===c?"undefined":H(c))?t instanceof c:t&&"object"===(void 0===t?"undefined":H(t))&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},me=function(t,e,r){ft[t]&&f(ft[t],(function(t){t.call(n,e,r,ne)}))},ve=function(t){var e=void 0;if(me("beforeSanitizeElements",t,null),ye(t))return he(t),!0;if(g(t.nodeName,/[\u0080-\uFFFF]/))return he(t),!0;var r=ee(t.nodeName);if(me("uponSanitizeElement",t,{tagName:r,allowedTags:_t}),!ge(t.firstElementChild)&&(!ge(t.content)||!ge(t.content.firstElementChild))&&_(/<[/\w]/g,t.innerHTML)&&_(/<[/\w]/g,t.textContent))return he(t),!0;if("select"===r&&_(/