From 33018b663329f938803787c80e893f017935dc12 Mon Sep 17 00:00:00 2001 From: Armur Bitcoin <16877539+armurbalda@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:13:13 +0200 Subject: [PATCH] refactor: move docs to gitbook * refactor: move docs to gitbook --- docs/.gitbook/assets/boltz-backend_header.png | Bin 0 -> 59025 bytes docs/0-confirmation.md | 29 +- docs/README.md | 24 + docs/SUMMARY.md | 12 + docs/api.md | 1343 ++++++++--------- docs/channel-creation.md | 23 +- docs/deployment.md | 69 +- docs/index.md | 25 - docs/lifecycle.md | 66 +- docs/regtest.md | 86 +- docs/scripting.md | 48 +- docs/swap-files.md | 35 +- 12 files changed, 848 insertions(+), 912 deletions(-) create mode 100644 docs/.gitbook/assets/boltz-backend_header.png create mode 100644 docs/README.md create mode 100644 docs/SUMMARY.md delete mode 100644 docs/index.md diff --git a/docs/.gitbook/assets/boltz-backend_header.png b/docs/.gitbook/assets/boltz-backend_header.png new file mode 100644 index 0000000000000000000000000000000000000000..5b913799f7908765078bc7d03ad96808b8a1021f GIT binary patch literal 59025 zcmeEvbySqy_wR#(z5)hHHzLv{9Rt3kbV@hUB^^TbvS?z=#C;%s(*pa^RH)t;Bz7;aSbOGJ5wiDLkAPU%+}7vgxS&9!NkPY z(cI1nakX9ud=ty*n?xN<44o|OY$;VOY)k-EXA??xK1vmn=ai4w9&u2zar3kB@w0PL zD#}rcimRw%#rLNG03{$L_P45A!paysS_37}P*jYC_obnp!$tlI; zg|AQE`j4llm)_S5{`-}`*nzA6^~&QwG{XOS0T97%`0p3)7y+kN_^0{axyts>v(u~B zguZD1^$O)@0Q+T~4vOPc_fesZ~YfJ-R2gaY6a3V=%}xP$`W z5(+M%0Jww#;C~7fK=I76E@}b($&N0g;pG~W>LdfPe^)f&{JRS3@+Q8QHo5eZ%e?~tmr!sC1;8Z~TtdMm z6o5r3m#p9t3NE4G5(+M%0L&~eq2Lk(>KB>E40opi#c;YYODA3HK>i;i%aabYEe>M z`IqkXBoO%5cl++%|F`gUd7BHZ@X|IHmbmnr3rk$?sS8V7;?0F6fJ>mbFvTTMTv+1& z22jw_tcLxo7U0qqFBahc3sgkh# zTBsZ-#sCuoJdkWQurXC+g)o$G7-!@2V=D61j_Kk_5y8Ru7HWlOO0a5$qHHc?@jB~} z%jZtl@-O=Mr-N>g|Ah6|=>@axMvX^8dAU0QXL*%0*EElUm|$fs;hs&$^rVenrI|K+ z`J{ee^%`UA%vHY{Npt|%eIEj|wBNmv?}&0iPWbJw$5d^SzcPCsM(MTVL0t~f3k)bX z+xW37a&(w#WbIXS$5mJ{F#k60OtH}3jaHFT3aqI^rTE`;yA{n9?QE$WR4s#I1*nbI zg0=Frb_0Y@;@ha#DzgbICMNJJY?xcSy`Kgn$%|isgD*=<3Tbu^W6SawR7Y5J28Jy;~h*kMtp!8O*oYNEZm&FfXJ#WB4g}H-2XWcex!c zKijKV*^e8-vwc=xtZI&XO0s)Dhtk(=^(l{6bc*N$fVm4tcE9mV`%?0;pWL&JmmYaq zYHzf?HQS-M=0pmujRU+JUo6E04|;sT8BWg$ytPN=XYQ{l1Z}w0Uk^B&TG^G~F8Da& z15Y|mb|I{FaXA;Kn7Uj@F>u*?9A6*h4ITG1W4~W=W?q-?AKGHl^D)%zx2^90%}M3v zdJz0hSlcIBwKP4u&-vP8)7lkfEnGb1ZMu6wFV4D%dy3`l1TGDDuwN(msi%UJ6#^%{ zEganfpJHv9FR%(5L%3jpvyT(+ZgrTXUct#OU~bbE{*Kp-cbnm5ZK~pz>2(@7ucs8V z9(3*bxVr*X!KYN*se;fpS(_9JcoN)_xH~1nlLB zlq8f|UVCU1ZM`@^&8U%Sh${T8U+MBjG?xD~lwu)7J&_Mrm+bVd;DB(?ou&0n*DjM@ zNe<~$O$jT@(g;rCD*pbJvNR?uvErUDP;5YA;Q+?SZeld4vZARO-GW~Yh&p7+2UqTk zi*Bs$?X@1n`zMHAIlbotiQj``>vD3HsM#I=xqpZ}oX&WfU)x9cn2`~mxY*5`S)Q+o zv``2tS%XMB-ftIx&Xg-aa3q=F9rquX@|w*&2Nw~~ELk!1FMFyC^SS=O3LQ4wp&A%# zC`2{y3>d@TUSJU=#g-ZObb1VStGeyS&)PzRL}7abTjV!<=X<_S28uf_7eD)(8Na)* zr56LP!C#M$?6eX4n(YP1*{p4Q70>;!^gP*Bo=gV>imeSHLSBoH zJ%0*hRvty@Ziv;_(wt5Y*nB2+_SnGdIyx$yr>FO3sNUyg%Rayt*E8bAzph)8LN1eZ zxZC8lq(oQdO?ZusJP}?eSTH$LVVzew=lk&a?u{r7s5#g167>X#=A@-(w{t(o-#d_jb|ol zcMmI4x6xAx?GT#8yDEBY`>Mb5!(?EX{-Zk-2M*Ah<*BMPHP`X81zNHB?Tx_w`)T0L zm?pT{QsM`%{M9_cu2Wt~VBq>KPAiB8YpM8|HzZmR56P0GAEv3|ihp>8EeV`%$kn;Q zEpp?+rKP~(nsQQguTpA+k}r-2=!U#Tn#?SocCKe&&U-eknYX`@(09tQbt5X4%b8Md zqhO7Yl;IcT*5henb{{p!+1ecJWV>$ZmZadT(9S_f0Q%(--h{osJ}rz;0{*6s{V(AA zM`Oqt6GZHt`kEmJj?;Vl*0zvoo^^8EFp4*@znyv2{uu9Gn(Je9Y(+XwqbaW>OfQ0d zqpwZbF1v~PL2F$#*;i9WoSge-`i&Xg!`=m@-^yz_cC_4>x;-L=8~61{Go*59^Vn^+ zn)Y)@MbswwS=2Ppx$`?Rt|#2mR}KoRv#0FxLB1wr2=aZgu~?(xKhvGeLwfyNzPKbb zdXE<<3+%LFU{7U4&~NsY7Ly{5zwvsbrAWywh3@aupf>6!x!CKFDmZ6hyCKQ6>;_9u4w)Xg87)`)<`}6^)+>ZlPh2(;EvoPr&2ddWFys_Bfc7^WCq2j_*5x8 zSV%gBFg`N@^wqhYg_mAO4eT#(UEd-H!9uI4X#~!D_``D2_?P8caNx}C!e5YUY|><_ znw~#)UKLw@m^q6Y1`2o2CrO)FpL2IU0kl5&ho0^7JXXo*5zRWYSI_UnX{t+pmYm`x z44NO>BtQG6Uy8{&fDpdxU>U{{yP&}j1bv+OvSjn-A=ipXvg9m3 zw@nTsG|qlPYFPA~UIae@?;1sL^9*Qk!H^`~My?fdP@141DdtpWW`D>JVom9oojmm< za;fplBZSS_gpJP$PD3D>!()h^_o(6|Xo<%v{ARBve3Em{Fa$6*XwJ2)Iket8{WUKD zXpK8JlCFbN_j9J$ryU@&0p<)5Rm=99-(70FvhaeIiaiav5bVC}&wob$i9q!xO0&conr9UC;xyJKUZCDVLE zgJpTf6~8W@F30PP#M1A}SM$?qalvRH$aWU^44BTKHZQL=?$zqb&C_`mRbMRMDArI^dUcZ(CACtsmWSN5JGbkF<0@80^kJ<|mZG*n<< zL}=dUZK;r&Hgjn|5qz`!vrkaRs2g{28VaBG)KFmA0X@9{aiZB!#&UyVsuPNNpP1cI zntJZr$F>!VomlQqI4V^n?CwU?4_$}St2xs036(5^=A+mkT6eQ~SVS-65qGP3Q&!JTQ?MdvIKoJLo1U;|XxWnJU^G6UE*U*CB zfi8z()xPo7ifrg?9M$K{rXg0Nyunros^V$}0g;eg2EX6vdyNNEl6nxh3E0g%s7Ga> z$Mq*}KA$1C31$kASoV8Y{VJDV7>#c%i;SZT*pp=6q5-YhAipv~wM+BT64!!p%Xnwg za@;f9gt>wD*IS|}ZGnq9NgSf7%Pp@b0@LJn*;djHt zQ^WODLHGOI{|3%$y@BwVfL_0EJ2r|hJf;;)fl4FfL8alM1U|C@4f~+$N73OYo~#sr zWd4eQITh@7o`e|`;@=J?8E4CEPAo)!c3~j<4UE)lT^`uCG`|VpXDJl4y@4@+tUXG@ z@d@+phe5Z&!Y3RI9|Wn4R^M9Y=_-ZrQm3g|flN8bex_T-eu6o(@}SFzlh~r`7Qlw@ zF?f3(A|f+flXW)+6`^rQOB_mX)JX-eTx$!pIGv*JyL0!If_Ai3Ps4aJof$bg?n~R? ztlESuECt63<=}8U95VhXw8Lwl2Z?6RYk7ejY@IF8cQoUiED;A zGZcHc!)cDO@q#q-bhN^vWCCWMn%!#KrM+Lbk*@5y8j!i)r7)VNRk|NvY~R%GAiGA6 zoO1oSGB-ZqIbk>u%aNY6N7%iX6o9o+THSh#*mdWyDz?;g^sXI-2p{{jRGz#unlyea zCYGn8972PYjQW8uVQl33d5&vfzsYrUi`?&ZhFjQ=3QSG>Ol2`>4oF->vJrSI9Qimw z;Cg?5sl}wN7({<>D~VIs>UMssvoOoqegcuX@5xpu@2N!^R1U9Ele^a(ybJ}GfwZ^` zpO!-RO+;A1=M~}MS~yqd2feWBHM_b(^`t8PrQ*d{%Y@oGQmb1zVyWw63l#@5Q}d6E zr9Xoi%=Gv@#tm~jeEqsQT>X6)=y>^nB>qZLy`UXkG_x#+TW7OX7g0O(b>iWkT^ZsX z;5JaAb%e6I-gdM{<5dXti2-7tZCjTi5gJP)yiCB{9_KRT<&?$eO+PsAQi^4Q(=)EY zf{zjwq`H{-T6&$(vz*8`>rtpJ6$qpNumX7{>Q{L@D5B$IML&7?Mk2vel}68F>3N<| z5#04*f`G0kk22`s(?FP zb|{uSb6c8wz7ND}0S#`>%9W;L-+4x-*zO8Zo%#K6^U@AeorelE0lJvsHc(wXb1bRl zn!5b!&5UvO%tW!RIE~Oo*75!!)MKVbC5h-H)b9GKdYEgSgQU*Mi%BwvI9BlS+_gd3e^$mykc7dgr}465X5!U%Timm;C5tH^T?cwgO}xPLb})EH zdHokl1Dp4_6O{hAE%V;Yi`D$Sx{~o*4W|c+x?R`W;sXtVsF0||2$GG#nAN}&Pgngsy)|bHK)E-NnFKu-+DqT2YGf2+b+a`_ zUsxwtxZc{x+UGt(s&(-F0eSct31w5hVsP4>FX>Y&zsg^)bd_x0B^Bp0BW`RuZ~q-t zIcJBQPD}c^U~X5N7^ht1^fyEZSzcFpH2aD@XROH{p!8`Y)d}%33sTw303$I$!97im z<8kD3b{5a6*B=M8<{_q|8U9v$XMNzDqvx-cQ0VBi%oO7+q&4>Az-AI91zDy<&5p^d zjSn4%#>ErCyOm&cW0hxV^Qp~dmDiw0M*}tojQ6H$o0h-1?VyrlrbYEZ>KM!pe_p<9 zdUo@7=XB@65AaXlps(4LEZ!vsySDs|9GGTAEQD;y(}Qe$$JH*5qZTLGt?zNo!BL|* zE4(XI19-f(u$I@B#T8Z4Mo6H>3~Na{nAv_K8Vo(z_v@;((_YrGV@WvocETIyn$4B9 zs(Mg_8aS%3?id)<3>Uo1I>L#oUzx@e&4imgN7GT_wwN=!KRva5Lj+8?Y`2P|7Hpf$ z4#qb-j3%jrrMo?<0S=*?QCJ&$$yQA~@rkjJ2`2AK^=3! z4hsV+OKZsy)gOgfY7OZ4N88#?9G7m57Lx1Nq_HMdXyIM~L2TaIy2~+a&%2z%+u3d_ zu`LN+N9yAF0EJcE%rJ*=rz7EHm`Tdr=zIl73wW*{JMWB2W?ajB;qNZvrajKsufc!Kys4E3qb6E>Co3cV`+z4r2SkL+MH5;P!zb;ZLs?CT^Fv*l5Qij!+rYFm`97t<@TAtgS2viv7-jRUg+8fc0pFG%N>XMTYMU0{RMfmEvlN4K~ zm|}o$G2B+1Yp&D0&UY0Q7mwCMr~9Vr5B+yZvxyRSl|L`GJq4+^!&Zbo{>e70^!V$p zIq1n*!1{8Yt5Q-4_{a04*l-ftcQ<#|-#HlRf;K*{nTZlrV&X;&nF?xyQc7}do-qE3 zF|7e$u(EAU3T81%2i+v2)YGo>@S$;yw-V_GA~i`jI}Z+-Z`*6op< z`G(+mc5_#`;1{HE!3J7$r#Wiy?K9S4L0mhpMKFys;OU&o#!3E^$GV$nbK1?GT#{l~ zM3`mQy*-#69cpq9;gdmFaa3|()FetUFq48x7-JWjKpAWayTPhC5TJMmwz$(d{WvLg zoibF8+C#P>IGh=u#`*ewq;&aP9C!HX_hE50l@N&#Vy@y=!ZDs!4WpG}SGnL~Nlh7C zW8Jp~XlQ?u%#l%e5*PYHaIqGH#sHMqDFVWtz?e*@T6vPaeww!)oiHQ4 zOL48Sw6oc+uEL*1dCe!=y&bMVoZjrT5#rRocj^!(;MF*%t5of0 z%O2m1)6>nY*LknF*A)qB%#X(g2Cf+&BGmO_aif+;_xOH&@#1*4a4L4iS;;$Steo|1C@L!u%GV4vK2fDPDy)O(K-`o> z$Y69qAfk6x*d*tyww3*5g0C3)bo=Q#JZ0 zhe$wuIlX|}2AudeZPMOxagusH3gL~hjz({@<*BRYVX6|Fg4MzuuVeolp5%-C`L>v+ zQCt3Mq8{A9;z@_v7^Ep%p(0_8w_eJGy}druAgqy3*U_?c5zNvX?*9zWPM0v1Z8MKJ z^j~m2KGBaORcdVtqfU4InyXDKK>O&b%{*QFj3eXu93rn^Hk@DnxYvAbr24tnbbyP( zNj}q-Q@7pSrP1$BcX9ia(jV~~TlYGFX}!UlxQRzggI~LHqGm|ypiOqhDjGLAR;shY z#4?K0SC~w$+TdZjza8CkK(X>+emlQ+4+HM+qXTe^w6}(vC;gTSYfmQbwH$T!-K>{3 z?@=pQq-6UsPEoetYiQBO4z3SIXbybK!)xv+TnKf)=Btmo@J6*vllM~|eiQyHimE2; z0zCKktMY1*$>(eHSV;*u130ix3c?;nm~MHoBZjqc#P;B}90BIhQY5u9F$a?s|21rT zQb`~FT1~Gi6#!(8Btx06V51YOOu&$WrEc-wY>pC5-!2|j#p1HXkWFQh4NWjo8+C6V7n;`-ObvnVV^u6TKYdTvifI6uSnba;PvLk4so#$ zI*&Q?EF4#{PpTv0;3n!w0(oj5Z;$8F)GqC@q2RDQP22KIiO0LU-o)?RGmhUu=zFo| z&OLk4gsT`Jy_iy487gW)I4%tC_-ZcrpDug{Q~vn*HC+eKApct>t{ZF3tRs9>D=CmZ zexs?pMZ$HWHv8?izPP7P<=IIA;3y!!&qsHtFDQb?t~BWxf5wfzmGK|h1rJaC0aw7r z=EQ6y%k+;s_YnW%a^W0dw%@yN6_?6VO3A44d(3rKE)vG)JHla%^0wS$SA_%SF;kky4HMwrlczqK?mb}Kz`ogv}2vn>8?)b+%OL@|J(;A=spQ{ zKd1@LoxBVa!{Gdqu0*51kHR~t=aX;|RAeAuA%;EzZfDso-Uc@hlFw3U=nkD=P5&vn z!gL6_`Vqf@hD0I^(#Jmf?C7(3{IRQ@e3+%KN>VfK-*mss$IYQU8dtQ8yH`tdbJ-Hp zP-^+cUx_a|z2>TN?j9+DF66NTrRsJ)VXecuED7}wGP3pTv{M^0QeQpdk5dM;e!9}a z=}1dTPldwG?5PKL$;4u8jY!djfzsTZYdm>h*A_+w`R5>-5==uAZ#1s&ktSG0!P}>6@jcndRM; zW0u&k85$aR6EF(N1ktceA*`!FV$H~GWNnoQhwI^}cdbwzRdgF?OJ8AjHl(6r%kG-B zbbz$FWGJ@8S1%Ll?(?vRz)@m7|BCf?2>0rfxJ{Jw9kJ#*knrpt0lMVStpa%g1`B?P zNzb~ML$rT9;E&tYxeT&Pk?lcz@OaXx=!v7Il@tDJ{Dx8z_@vu-Esbe*BTlBZP6NB1+hmdW4`M5Qw_#CqQ?^S^BqeEJ#kG}`MRd2&K` z2eFu2)#T(*>dpBu9jX7t;=2Pf6x8^7Ttu&%a28c0k{s3?>#4qZh7?ZjR|wY91PbVo zCFn=LmeGi!FrQRyzn**S#jP#&C#q@r{rQ1D{pF!PmHH%aR@-a!M~qTDf@%d{OVhKA zt;^-33cS6=oTn+yZVn zG{P53>hZleNK?7CFY$O*WHf#MI6K!L+y}T9bB5BZP#+$FTlLqzXz!BZ{fSP{ZG39* zhExhAx#qWy1g~h+3S|tGio^*r=Ef(7w;L6-uDpAyD<_RyiF`_jdvxWKP+%FnjJ)jaA1QWW3{1WkzEjplI zAThDxt#-2wCk|D0?q!KbcH+6bSAIm+yYC;{%JaD&76eQ7WX-&HOFl=i;p$+Mp=37s zhyE7Vm?shA${ju5Xc9f0X-GIJ z5x2;bl;DXm^>J*>xvCF+=0^_wKSp5~ND-??4BiaW+<$oMNW0UPXu`!-q}bE>(93A; ze%8sw*0TDuwE*k>F^;Cg0}5E=*HO*E!^UF^=bT;HHo9008PTf6jYk6t!O{%JQ|2Ra z;m6w*4v=+EootH4{@Z&B^yH;m8Y7YEl9|q1_e`{kqu+nfC-X6J{=06CE1P?H7_}OI z#eME(R2+9j897GXuAb`k1eMsC2DNO`=#tHSn-FU?{uzI1uXQO4vU$4DDq^TU&(6&Q z8%+6RitqCsWHtlMbyiEo>3ydQ>8{6CsDSefC> z^8``ns7ZXn;uCj*FuudZz22%drK~S#-ce8ZwTfPgd{tkPxLyJ7n)+IpPGLPo(YwHP zKcNW+;yO{ahurEGg{==4JBbc_biqxzxLv%ftG+kc)F&ihvg3m0P5U_2dW;svs9^EE zsF82PjodP1B-x?%f=1=zJvz&EPRIU3IIM=W@9WU0_Hk53+(gMz-$b31Nqh-NO51d_ z@|REaegXDlB%koxEv!v{MMVptAdv51_e7FBgCeS4xz3&p8C+ry_3dNsDq^&Rz% z{RxqCZ2urg$c=^zv!1XM2Lr$FIr7GPrQIW>rd?+I7COzH2WOxe91B03vLZb&pL7UHuypO9dlHm= zB1DxXgJ4$gdf(EkVk-I6RVs7s#6|?=F{+L~5=%i5n+9MvRFtnJ_CW|9s*?Botel~h zaBg`O>7&F8MZ`W$UUSi_$g_-m*vT;N?1{>V?OLE^3tgFPc`zL?3+y5KTV8z{Z>d?Hg%Fb)XFa0;@b)hGsQEK@!#oU;M1+9~d z^{leNQVd62GvK^71qEmeL&>6)c%PZMP}1oo5$AQboev>}&`tRQFKHg)I&6>4ytk}0 zuI)PT4ytm-RI@PurijF9c!R$fOu`u1j-C##;BBEd3rqEpA41;|81EKUJV2-9J$~*G z)VhN6?dFZU%)M`hR2NHU{gN#)u@|BS*n)z#ckTtLL0kam2hL&U~{F2_#TtWImz|yY)O22ZX-JTjo9>vTQZ9w z!i7VcZ4aJmn%cc^sRtq-o$T0(b=Q&ckfo=v)K-XC@eD&I++u7TmPQ+odj$aj)USpN zZ$1_ieu=-`lCt%u^iutAuQC%gv4AiDrtQrB_|@Uari_m|LtWii$eW$HSVMNcI12SR z9AxM20_6Qe-6*AUbHls%ALhi^>11EsD=S4;s@5KKdhH^W1<^e=0O>A9g{jw*A&8bK zzeF`}XnNel3TwjEqVC4#zQc((%vr{`-=c2EEPtw?zme)Dv6i6J&EkTuMUzvPT3Hwq z6=Ep&!DilR&0LJ%L0>?49^lpVCJh+ZGj1?rYZ9)TFkO_ok~d~7L8@vRie-l8Wk>{WwS)V)qcH1XV2BsF|OrJrZ6 zz|6Sn#J!p)(ANuGnTa0b$?5Pp76xx3*CR1#kf$>o*Y|}HvQ1klv$wIv<=iB`BBfB1 zGu0LxSBgO^cE?i7GWWudpDs-Ar!1Be7?{bEs!eOttCK?FLzOs_=0RswjSc$Lq8d4Y$sy<8ihc;(Q^b*DjGF1H*y^*Y331{KIsldhx8*3r3M z*eq$9$1)IR$HwudqL@CJn`nJ;i)8NY(Lz!2N=`-#O7eg1V?_ z24rXGFF-BjsSDwcrLQn-2V3^dtSgUam`aTfm>yJ@TbCGt#;PD&EXhqK{pE$%jEr!Xt6_PD61p~{pysnB zsIYUdGkPgbi?nv5uC}GF>ih073XKHZ*TN7jTmB33rV*B%b1|4sWnHQXS3?o#%?*Vc zZr6ikVjYEVgOhK{GA7&^A7eLRM%}ZWVvTJP1hU+#b_tk?KgqClvy;SS-Yd-QosP;x z9bb36Z>TQ0W@U%AJ@E;LS=Z!vM`g;u4$bWs3(?MkH3Hqd0kK5e!s+<;=TiadtQC>} z0nr9i#xR+^?G*rKo-(N6dhGq5b`;aHUz)GVMT1uAmnXyN(yn@pd_7*(!zkOb4B;27}(BrKf`A+j3YkAqUyt@3)trN?f#Z+2--jhrbUi(S!2v zW9hOd>cXG5!2;y7_T~CNNWl#z-lsfjY==v@%GtmUiWSQ$yDRykxon1Y8*F5 zV_Ti0ZQpLuiq1I4hQ~tBEAY+-(PKJ**9#%wgsDW0+^9i8M>GMwGQkY-jt{i1oRRul6F-en6{=o7xN{DNTmkMBJ;_@lG|WisF%w-u<+{26Y>)a=W=%48s4R=FK# z$2jQEWmlXS#%v8a2KGBX>h>MZSTH+~wmC(I#3HT@k1Z#L0j0i{a_^^#XvX<#TUr-hCtKu5a{-AB>R?Kqz2zOwxmhcqTD7EX zQ{XvHev^aQHW}A9U&Z(O_9Fo_5?_?d#6#Fvw@rCfE>D8N1(B{!AWaR7+BQUMPCyMs@JzBIa9dwn;OIKtp4H!P z?z&n!T2NR!6l&KU_>ui*y$SgYiBT4HnWnR!)B1C$%uio^!7WqOu$sF)L1$%r;8L@F z@lo(UUvfYV(~nfw)fBvO3-ePagpt`B@wv%T<*Xss&|-(uK_bj5 z{ZS^s!1lrV+IW$-yK$z@5IY&h>HLRvxAT%0x}~b`nMss+B!ZS#SC3#PLn|81^P|#r zQujMm{mknhsRj{D+>k754+o&0>=qu%T=Lz z2`k;!`NeyoL_3So9AsCEdfz_{_4by-L+qW8LXi@u?}9G?jhhiy`wo{o*qL>-6100D z0%Mvr38HBGK5j|rVFZ3<%jLT$IjEBh{5g@23Xp&AoZ9Y{B0PtPWz+@uk8>Hg9`dp_ z34@XKqjA)!-}y*sKv#cENx@-5V@MBIQb{m-tU7p8v`FXslsG;kS@&rs>);VF>xfOb5}+7#h^xV zxO`3S+iv)UH4Lm9FLeAb)hK^cu9_$J+WA$7HGyNJn-vT7A^G(&OPGB(fZ^%45%JDF zdYWKveE-9)Q#%EW(~cdf*sKqRXLz@Kqvr&b@Zs)rF3;FgVxM?1=hdtQ5BlStz9`*1JU^3(Qr?B<4!tz%Lrxqumhh$ zeN~Qf-<%D|86v|RteAjX@6AQHD=jQ zN~w>XoBnR}G!8xS4w!wbfCRqE#R>k@Refx`%VJEZ0L+UcW+DfF759b8E`1|`VID#l z+A$Ajv6`GA`5Nk4Z6a386=j6FnzrDnp0L34?y>^jPnybX-6$Ri`Op;YXOIrn4UoSo zU789~rsd8TWFh0fpV@X|^7A@&N&|Qz`Q2{qqw0O4Z&nu@f1UA9knv>x@P3eXg$dnT zC0km(xxCvlIq?y{o15B%!1emT=b+f&yd2rr-r6Mh*INx<&yO^-Uz|00Q8sZ}vb5&$ zAN|^>e5Z#Uk-?zoA(E=d){Q(BU6>V0u&x}z3ZfV5&1r)*04n?7e_RZoQ+-qaob*S z`n$d^fG;FH*6arEz@Su*-}p@i1H3 zs(XZvY{n9+8t3Lqi( z?NV57nNZ`K+sA_ylJZbn{Yp9WJ35eRH{wqmD!xiuLVDY?bL7G(QTQCIp)2)yZ|hh| z?dKNo4dZ+$!aqAI4dJFT<(JkQSZTd-SU59x)aobV5}ghafOY_zOr)DmV|<;X&SM7A zK10^eosOP9)vAkjeY8JS`Q3sqG;s)z%}(cLvc4kmDGN@}Zg*Zk81OK$>~{i>;m%qE z54v6OS;YnTRHJK)6t%mCIV-3jOnficZ(iW`w;Y-4>Q;mE^=y%)MQ%jKx;qk4ElfwR zq#Yob5`Z9TW7~9Kh5Xx_bY}X+`5{$HG!-;Mw6+aSTc=ScYz^ygMP>YIQC7P5NXRK; zv$}39Pi~liTJrs{?z6HVu+Jabf*0f#NUmC`!>rx#X4|#L_9G1$|HNi8Cp%cz(#|d; zQ_ylJZ1kY|D|#v7x&epIegr-lgn^L6)l-F=F%gWklgR|Z%XiVICIw8vGr+_l-1Pvr zZ{Kl{=vxV)y>KBa)J`%x*={_8*GUO0?XmLlg$m~LPh1h2tqScraQvjkea-mqwSqDH zEUFKkc)vREBlBs7i~`$M1ScKw$pe7R`3%tr{@K7E@+7qj1rD{lg%{BOu&eqOEn7K)}v5M_bDU$sL*uThd2JL_N8-MSL-1X*31;--{14%&Z1 zrI%)RN5{+m6rK`U-`f6JK8gi+#4V7Dm#Y zMO!nzO-7KNpAJOdQTP6XuXT%GCg=el7UX04Y^;L5Fkk>!_%Y1-eQa|sO#fYV3hngSU+~i3z z3zkJ=Z&BQ^+Xc~({^u0B=wX2PPLr$mO|ch(XNUXE-5gjkQj6#q6kmH8Rlw}_$5fIVbM9jDFns*$ zPKLF-gJY;eLAGkElB2Yxlz-$CDY?#2;&{@01x3z_P;|soy%u=x!H;iP?Xwwqp}93g zAF#R>lsdiJj-FUys>0VoFrN;`>#oAzVz4?a!ThEccA3WADi zrcd{g0-!fwZYE{Xqjqqji{ALd+a-EQtzh;Y)*YwfkJ;6%=Dp#^jeLKulpd9I!U~ z4iBGJDx{>@5b2l|%-1oSxBn}}8LY6lY4(uQ^E$FiDgT}MJNcR_>15{HAn_^FoG{0X zqf4mL3cWZe02Do43USZ7^u4<^Lf}H+$gd7{NH~%=)vg=tn)=FJ>xdZ;tGws@s=S>Z zx1{h%b=voL%cC(QkC#zvpYh2`TnC+kUw(O(sjs7-bDKa+RuXMA4=jH`1z>D(VfqXg z6v7g(I|N@)ci(C7gyDRO_!hFU@;yRHw;n&ds0H|0l-@OPz+CHHJlLf@QT!1Uy$$5w zTf_94pU`mPQywD&RmV2 zf2If=x4gwY@3H8KOc1KV8I(!34tJvS9U|dQghT6OOgHr?sa;C8_KM9j6IDK&iiWu~xnaqZ4VcwCJqSQ5CG{ zKc7r}R4**r<-C1>DPZS1rsc+rtw8NkR9aK|JSVY@!WZEJmXLvxGFV-O;kf6>KC$Qd zVUh50^-ZGif$(F#K6b?`{AyCh{v+Ax=M)*g1XabAE&fGEMQV33iIiB4 zcNcUAKZmKJo{2bY?!=0vsLWSWm+Iz3=o{zvoR$R8>>OqtFv~=HOl~v81A}_^Wt3>J zb=2E=-vQ|>T@3EGQgk6r-r8&r+@OkfCr$ZG2$Yq6+M|++f@h(!85qBp69m<7A#E) zq(7-F%MM&+qlEpfJ#rwRQS=~V?g7{v<$`KdpC|!MKMc0`z_0kZ<`Y_7m7HkYc_ws8 z-J9aFxKq5L0vA?Od>}Y+5y)h=m*P~M{T6Xo=kZeJ`Rwd9zLq8SO;xEvb4Qr1`2Ce6 zwFSj(=9&V*8m!F}uxeuxE1s(;EHNI(y8SIYG_<}%+G=pijj-{1t)qOpYiDfei@TgD zF)+hd(#S)yiym>WE4ZC+r-r+r8Z8V~A3Va?XLl$_|CBtY{rTuS+AhAq7))?&>C3y_ zXjfA$K`-Kl7*M*dNb1X*sK9DPuJG8HM}x?q9HhQ(PT1(s|0TG|u+0fO@?+I#Xr~xzQg~Y1;gp*0YNO!w?A|1KluD+lk0s(EQ9~=K3i!>ej}0}VdtDy|$-m`nT+FIL_)jf_ zF9rz4*H?*x9h4cgW2J0Vgi5N%oko?U`f%Q|;O{t18}7<0SjkIs%&7p^tX&$zv{lvb z1>fYZ`|1oybk)v$*!?yx^vbUZ+c8tFqT91Fu_~G@WRC=65fuN&&Lj|VPh)QF%1fcD zvgWSf`I<@oa^F1;y)_|_ehhI0v&(^EIQ`Cw5n^hkHmtdQ&aMB-@Y3s75&Wx9pgdH= zksTCyJy;P&phkwFq)swE#ImB)hHH7zm7+nO^ac1~C3rl0p4D7nM=y)!w(1`~$6W48 zY{k2>(0fk{gqk?{r+kShuj&o~mDpU(yG)bnz|_wooW;k9-2kX-+NHM6SdX8zb=hIg+E6VAWsM^3iJ}7X(4EQehp* z_ZC-`WAUPa0X7uDF}tmkR%kPn<)Ujk>_7SO5964`o;#c4 zc{>;hY&zIp(8{W#3{Y6X%o5Fnk#t!XdvDGyBgAP&P#h`F%0vPuT^qjmI%DbjVF_#X zMN(0-r?OqOWAou`2p)!4GKTE(1amfyfD+*Ev%NNFfgod^V7}l1!2UmS^m-0h<+2oT z9UbVnkb^#=&ZV*DV`b!P*VSb1kU=SJEnrQ< z;$)dAxqM+^DODz}Oq{k)3e)&_IvkY2GT&Q}pWGj=ODMOTcPDCemX!lllnWc&Q4|Ef zJNdg&@Ne{Fupl*ioq}t$%d^%iGWBDh`JidM2Zac6kO0cIeSxWjKC%49hNR5^F<>$d zCwK-sKDykA!hbCh(ud=jo;%)$s<-J?gSg4{>!F* z9z9KnoC|ri0QMJp{GG_I;Sa(TECQ)~MfZpt`4r41bTV@sc_~skRU<#~yH%nJ=V|rB zK>80VUY@j38+oh%qE1&{d#}r)@h+5S^#ZSeW8*1ls`Ekr<-3;X$iD`qhuF7VgE%^? zNJaX9{A)!asFc#X_gf%73sx8NdSbcD&UO?D7`1fUzS>{Ubn3>CV+g{?_T3+bvAgR% z_a?U%ea?B$I`3Y4 zt#|GH%_M8EE0~Obk#%=8Q)&yhzW$4o;gUi<<#o~XuigK`NY1T>8l68gXg;}dPeK3) zb^vLw0EY%6M99xNJf5C{Z2Zik8C-yn?X&<*f_v8`?L-)r&(1`SWF=H} zkQc(zoRGDvqG>fYv!i0E@^phMojo6Rl~9$C_Bf!Q?6qGKo!O5~ zf_@#>`m}dp8w1PifG*5$;S|}=@b-X7_vCp(xGRL~v+Zc$-1c#-qUhq>?JH`j>|u`= z7FkSTYOhl|2$*a#pml!tmd6b*s@`x!r;J>7+}vu+hX0x78$gbAO>o{s?+^9VkO#9- z)p~&YdLEF2y0%ES{T?Mpb`!23>~ztxv>DY+gh7sT#J&@oVlyTFy_qVCyV zLKp*y3uaz5x7xqlokt2N-?C(MCwj0t#13HIDe86^23y^iV)B&$a@sai9iqx|JQCc8 z(zcXwb>2pCv$_Cr{-Ey=KeHHyZb)up&+-%HIQx@RakFYH2L-csN z?UA8t^*q-NS@f#ofZV{qRi-c}Md3do!kJz9y?+UE@5rD1m?hJ-!vG)HZTY!u$X}KS z=sgWF=1-cxdwutq$|{-$h@#pJzIIPm0+@e+7C?}L{IH~ z;41<0;$M5Lu(D(@amNoQ-xUX$_m$^01EPHpAjaTqI zD08V4l2$Nem>89gf4!dT5lJ>~1{^0uzT1*h90$ca^v(KNo8Q;N3!;xaI(Kxr8W33s z`Q3Yb{~p}>8ls@M5y7ceX!Uw{sT9z8K`7AulK~NbPu18vG2fTbB5fv~FYvYgW-)C1 zkxlO^%ROaWOzznR-%pq3e-O>sxxH4qTSc!5KCY%k^)aA5_+$ppFwVh*(1$5h0LOU0M7Xyv z*&GKE|Ad5P9(kK=y^UCY<&pGE{n%8D@zZhMM!@3*^3DU+Zw~>%<&J0gRKcbLVqU20 z-tY32ZY6icjSy?**L&v3W+_Jq*o5cU#luaL8GNCt3sJpkrj&AGOpE6;P3e1A*$Y3j zmFAoefdgMQkHmJs>HNnmkWbZ3_1<6>+XuX`$qJq;PWTXyD9@q-9j8 zFXlCfI0LBs8X$P{@?Od3>}cs(UX^TN(0y~wTr%lM1!jNn=!^epx9=P#B#?1{bo=x7 z)yCRnu>6XViK5hHNAb7juj+y`1U}E6)Ou{EiF3@h=i~?UKnfzx>Ulhp?rDE$N=an{ zew2NKks1*2e!4}>Q`i#E@_!0von%JQQUkA z@0g6MvQh7al+YTc4y}OM;ZmDa{W{LRo3FokWhZgO`ssgK8u`9kw)CvWC&2wWzuip6 z`#z`VUle|(rK>bsv0E1ezlckHKhDRna-QDDa6U*4H{oL$*PLjs2^L0qUPDo)C}&=i zwSD2l-cLdms8CVgpurqxJs`9l8Qkf#;|aOGIXpd?0fY|?FZ;La0Zu_+#Gr5k@x(x0#`Xb*FJQG~ zRnGInDywgsHt;a4o2y?MRoX1LKFiw(_yG4Gn?8s-P|ky%M!cWd$IAD|*5Ip>d}+#1 z0CGCHL}9B{(esCSv7BLwaNmopABrihc#I7l=$z|rmDqqe*`$~6K}-`u&A8Q^;Y|I_ z?P*gnK!QV72dX}(TMgTG{C@8N^5O@$8y`^3V^*4z)UtRzVh)~?RD+pBa&(b8fY6I? z$HTG1zGG>_@=4caA~ida!WzL%ZjrttdbmTM;@Hl}$~?0YNip0vI?&%E641%9(l=>( zS@hAtD~cnrti4Bs0a4$f_-3o*HRsHS!L?_qp7hn`U5eI71q2$InI}}A-1zO7UMOJN z57dAlNhe;bVE;)2P5v!@_+=^~K-%P|ggfLSzG$2Ze}Q77%;9aD#qFEvDWvA@H7-DB{-Rs-2O}WKF&{Qa zkGXGnoK^CPk#ZcS@et@CpW98lZt!X%(z4a{l@bhTDR^$F9Ehs(aTHRf_HQPrLG2(t z_FlhOp1psy(0vG5MT#sLfhmF@li!?}hYfQ&yyOZmk@H-24Ya48w}X6dW1(|dbOe_N zn5V^n?mnvUJt4qr!_tutI0XB(WIsH$5{!BjK`YEj!My|eUYHajxNuPV|q)guoCy&%EA zm51+{OJjEBiyD17Hx>ryuf#%4fpJ%d>-mc!*6s%S3MPOjD7ZTIE3NDF$`Rj+onkJu zv(m{LM!!b}I21Dv=8u-|KCudxn5?29F53gK6ethKs_vb)lGzZ>BvN7HswGf3p#kXq zj}_|!<*!`ZfZEpF#Ma!7-6q@q;A&4bPFZEhC|A2E}?RzG{6Vbt7KKs76 z;&$P&@uF2i=U)KhaFKh9du@XfUO z6XD(C*6`UNi}R=Rpn#ZaCjh*uF@1-1C(jeP=GjUI+WZEHu|Jdp0Y1E(R)?15ZLcd8 zKsBS?_E|7c=Fn|+C;vcM1OlP*ZtPqBH=8COX8wp=`sM{2HRh2=IVZZgQv4E>09AqQ z@Z)rKG5+Zv6tqWf=ZgzHhcJXl{l&J*L#HhNGSJCW2tRr~KsPH&=iVtjW}(C8UlcOj zvIm}Bum=}bsU+VYOwPVgn1(vsH<5Jj+*OM|)M~kJ-9CE4`R?tzUl~6RwZ_W2Y#r(} z;(zHGBR@q(nmbil+b%{nMMkbEBKnDg9&ZqH(n?IZ$nRF-m+E}DBdrCD(US_2%-2i$1rLlo;3R?Er?5j;)r3a z$$^cC!J%In-zvVDC$yAUsLLPj&0-RA#3&cf^1BbWe()bR>&b+l-aU}T-Mw;jmx!lOV&jU!83fUm5yEhbEOepGj2nbB=55bb z`>piX8$Ac?>?%s$4%4nGSXQKqyI9`vZfzEgqmJdUYhFioheb6>eM=G0S(c=3p3g(* z0uvr>&RW=1TV&Nt|)`|=TG7WZ?+V< zvS18k3&GP&)W3@AyHX- zPt;}6y$O&-zoRw=2(l}y)q}k4hEjKwH~Aj8vaZC5*)$p}%8L~_WWu9nW&m)c7KaNg zI}35Y-MWa>CaG3TtfNa7nat}B$;E8C%z@>chMAx}+^&Nk4cTF<%5=DLTAhsu-`GpQw9FN! z>_{6VUcj!XZqxfe1WI>rX3C%Moa*(3r|XA`I|4j>kb-)nypIQU?ImxHwZ&fw@$hoD zaTqefiR18f*4Z1~9&G^yLNQ=)E$fQ`iAVLU3JOdp{Sr}7%^fpnk5yoM8a!Zl9HH-; z!STe%_+b*phg<=7XrLa`U6G1!jrfbX3@(M$un$tRxrBEiUe-241-CZJ%e|LYHHl5K zwhg7s#SjtTX-d`W%Mu=QjAsdw^m!)N=j1y7aa6e&?7Y=u;6=!XJMbUH>aI=oal2MH z-v{fD{GdClYgCrcVlUA%t}245{>7Yn+_$sTg%OA8c<3J0%&}RIAjn5 zZ+xoZni)rzAfx3yrX#n+LfSE|s_M@d{BFsQb^p|@Cq(p&)3F|x%Ly#?`L@s6m#^qk z>nnP`4FrKvIgXfG`vK@CZejY=`D@Vb;cVD~8U``~u7qLK8AYew-|FS24_mZiF|Yp2 z7*A=xJ5=1zX#Qr<$MgnwPI)N{1-=?AYUX_ya||V`8=|BvSdz%-gKLI6 zgegGHgoO+zOQ2u7TA*OjG_0~*pLiW=`VtG7B0Xx*LcPk zco)wfrqG>zU2VRx)M-%sz3AC2WFkYaVpe{9r9HH4WeZZ?iGNJ5!5E~<0$|PY=VTO4 zMbLQWn4I5*;^MLPLKV4*g#1}x{+kMJIC@mU59?a(LRC`yi0~5F?N>ysfId=o$*~bv zEHPeY9E~Q1>k-$3RW)#?f^ozDYLNk`NR#bmDzmdx5vz}vvhXGP!AQ=0qzib;Opd#~ zDvgn~NG2{l^_>&9rmVeqyCL=+p~{IX7)jRY-w5zgjC6 zWD;DgAC3E#4G%Q!b5dcWd~A|hBYw!BPNfH8*qb}|>dnre5`-!DqS>f_d7s4iWN%Q( z#Nu%uP1lAGbq*^5?t*5W!G1o)oVoHgH_S*~PV?2yz1q4{QPELAUnq;Vfbzn%UtUUi zyK{BMnw%lb9WxF5xsm>L4s^$#Igp2bo)zcJw}6(6!rJg@Wg9- z&kD!GaO?GLmG$G+r<=KW5MWt^ipG54r%!^G+sfdx^L&;qMO;Nr!j>&ZRI*09{BhAJ zgW`1XoWxBBrC7Q}v;M&D_DezC9g*O*;Asr8bQt#CB{fluzU<@8In)N;I(DNkLO1A0Bcbye^!5J6pNShuR9YN5I?ebk=h$_=mfG6U*^wV*(Ds`<3Sl(95vZRo}o(o_0JlI2hC*MDRk zM8i}Bb}q4Z&av=~T5h29+x78jZUl6F4Y88Nd$z--4p|)t_!WRFC>EaW(9jhf1?`}V zuG({df1vj~m74b#S@|LDe**3QNs=N?DcW+1_$Q_zLnoCb$80@rLK?E$O2~K{!RqV_ z#kqFM%D94C?5zq3oIb7_I&xFrkZkT>b>zl>-1@>ebk3riq%!2L#qDG|?9aORv?0ht zd>m*aX>e_b+P{N*O|MXk34O0f$Ux4$ZRe=(wjqqCYq8bOAEASOL;6WQr`$L*G~-Y|K(8`XfM&_;yE%q048oSR z+3af+u#87*cJJ*&2zTr)IVVBOKI~;YJL)1ke^R$#Qg6UhN$#k&8v$IF51B-JLq5%` zXy8zvVgg_m2(WQ6Gn9h&-}Vr<6gjt1EAmvl8CF|m9T*ZO+Qkp~%r2U=_AS2UX;Hw% zb?y{8ur}#<{F-bzc+i6hU1?k&%&y`vqK6&Z4_I`Z87dGo2BzZROY57cK+t+^Dh`)v{tOienx{v_f#!Bn zaiF;nR2*o|)gBK2!!E?K;`|_b=TJ45edd6=r#(9W8_=kLMg=q~piu#h3U*v0nx_P!d5<)Yn&uVIr~qKYewm|Mm3pkNs!!nMCR z%pOWL{{K~*!2Nd}3iUUEzt#K=>CQV^BOn?kAex=fo*fz$fM`?zEZj=#GHBf>%`2c$ z0gVcPtS^lUXjDL>0vZ+2sDKtL*a?^Xe~A@5+;-ocB|_xuDEyLaGxyH5?{2i<9xY2n z%Tm$e`~VrysDMTVG%BD`0gVa(1pZf0!LTky8w5HQrmlQTXV;qpUT8`HT1WQ3!+L2J jyN>|PV*k%s><5rZ7roCM{S~F1o2;&)sho4$;^lt;?YH*+ literal 0 HcmV?d00001 diff --git a/docs/0-confirmation.md b/docs/0-confirmation.md index e77b9aa0..0161fe88 100644 --- a/docs/0-confirmation.md +++ b/docs/0-confirmation.md @@ -1,26 +1,33 @@ -# 0-confirmation +--- +description: >- + The use of 0-conf can make swaps a lot faster by utilizing transactions that + are not included in a block yet. But accepting 0-conf transactions doesn't + come without unwarranted risk. +--- -The use of 0-confirmation can make swaps a lot faster by utilizing transactions that are not included in a block yet. But accepting 0-conf transactions doesn't come without unwarranted risk. Therefore, as a precautionary measure, Boltz enforces a few rules when it comes to 0-conf. +# โฉ 0-conf -It is important to note that for: +As a precautionary measure, Boltz enforces a few rules when it comes to 0-conf. -- normal swaps in which the user sends the onchain transaction, a Boltz service provider is taking the risk by accepting the 0-conf transaction -- reverse swaps where the user receives the onchain coins from Boltz, the user is at risk for accepting the unconfirmed transaction +It is important to note that: -*And 0-confirmation Swaps are only available on UTXO based blockchains like Bitcoin.* +* In Normal Submarine Swaps in which the user sends the chain transaction, _Boltz_ is taking the risk by accepting unconfirmed transactions +* In Reverse Submarine Swaps where the user receives the chain transaction from Boltz, _the user_ is at risk for accepting the unconfirmed transaction + +_0-conf Swaps are subject to network conditions and generally only available on UTXO chains like Bitcoin._ ## Limits -When it comes to accepting 0-conf transactions, Boltz has configurable limits in place. These limits can be found in the [`getpairs` endpoint](/api/#getting-pairs) and are just enforced for normal swaps. When the user receives onchain coins from Boltz, he can accept any amount of coins with 0-conf he is comfortable with. +When it comes to accepting 0-conf transactions, Boltz has configurable limits in place. These limits can be found via the [`getpairs`](api.md#supported-pairs) endpoint and are enforced only for Normal Submarine Swaps. When the user receives a chain transaction from Boltz, the acceptance and amounts are entirely up to the client and user. ## BIP 125 - Replace-By-Fee -If a transaction locking up coins is signalling Replace-By-Fee either explicitly or inherently (unconfirmed inputs of the transaction signal RBF) Boltz will not accept 0-conf for that transaction. Boltz itself will never send transactions that signal RBF, which means that the user doesn't have to worry about a lockup transaction of a reverse swap being replaceable. +If a transaction locking up bitcoin is signalling Replace-By-Fee either explicitly or inherently (unconfirmed inputs of the transaction signal RBF), Boltz will not accept 0-conf for that transaction in Normal Submarine Swaps. Also note, that Boltz never sends transactions that signal RBF. For more information about RBF please read the [BIP 125 - Opt-in Full Replace-by-Fee Signaling](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki). -For more information about RBF please read the [BIP 125 - Opt-in Full Replace-by-Fee Signaling](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki) +> Note: [Growing support for `-mempoolfullrbf`](https://github.com/bitcoin/bitcoin/pull/28132) in Bitcoin Core might make it unfeasible for Boltz to accept 0-conf for the Bitcoin mainchain again. ## Miner fees -Swaps on Boltz are based on HTLCs (*Hash Time Locked Contracts*). In order to be able to deal with the *time locked* component of these contracts, in scenarios where not all transactions from the mempool are getting included in the very next block all the time, transactions locking and claiming coins from such contracts have to pay a *reasonably high miner fee* in order to be included in a block quickly. +Swaps on Boltz are based on HTLCs (_Hash Time Locked Contracts_). In order to be able to deal with the _time locked_ component of these contracts, transactions locking and claiming coins from such contracts have to pay a _reasonably high miner fee_ in order to be included in a block timely. -Boltz considers fees that are equal or higher than 80% of the `sat/vbyte` estimations of the [`getfeeestimation`](/api/#getting-fee-estimations) endpoint as *reasonably high*. If the miner fee paid by the transaction is less than that, Boltz will not accept 0-conf and wait for the transaction to be included in a block. +Boltz considers fees that are equal or higher than 80% of the `sat/vbyte` estimations of the [`getfeeestimation`](api.md#fee-estimations) endpoint as _reasonably high_. If the miner fee paid by the transaction is less than that, Boltz will not accept 0-conf and wait for the transaction to be included in a block. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..d5df6b48 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,24 @@ +--- +description: >- + Boltz exposes a RESTful HTTP API that can be used to query information like + supported pairs as well as to create and monitor swaps. +cover: .gitbook/assets/boltz-backend_header.png +coverY: 0 +--- + +# ๐Ÿ‘‹ Introduction + +## Instances + +We offer Boltz on [testnet](https://testnet.boltz.exchange) for development & testing purposes and our production service on [mainnet](https://boltz.exchange). + +The corresponding REST APIs can be accessed at: + +* Testnet: `https://testnet.boltz.exchange/api/` +* Mainnet: `https://api.boltz.exchange/` + +> Note: To test API accessibility via browser, simply append an [endpoint](api.md) to the address, e.g.: +> +> [`https://api.boltz.exchange/version`](https://api.boltz.exchange/version) + +In the following sections we'll walk through existing swap types & states, describe the REST API, how to handle refunds and more. diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 00000000..e68927d1 --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,12 @@ +# Table of contents + +* [๐Ÿ‘‹ Introduction](README.md) +* [๐Ÿ” Swap Types & States](lifecycle.md) +* [๐Ÿค– REST API](api.md) +* [๐Ÿ“ฉ Refund Files](swap-files.md) +* [๐Ÿงพ Scripting](scripting.md) +* [โฉ 0-conf](0-confirmation.md) +* [โœจ Channel Creation](channel-creation.md) +* [๐Ÿšข Deployment of Boltz Backend](deployment.md) +* [๐Ÿณ Docker Regtest Environment](regtest.md) +* [๐Ÿ”™ Back to Docs Home](http://127.0.0.1:5000/o/SPM8mTvJyc7OIzGL3HD7/s/XUXMXrD8YTzvuqvAeom7/) diff --git a/docs/api.md b/docs/api.md index 8f27aeee..dabbf9ab 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,83 +1,42 @@ -# REST API Documentation +--- +description: >- + This page lists all available endpoints of Boltz's RESTful HTTP API and shows + how to use them. +--- -## Introduction +# ๐Ÿค– REST API -Boltz exposes a Restful HTTP API that cannot only be used to query information about the Boltz instance, and the pairs it supports but also to create swaps and interact with the blockchains that are configured on that specific instance. This page lists all the available endpoints and shows how to use them correctly. +## Basics ### Response and request encoding -All the responses to all calls are encoded as JSON objects. If endpoints require the client to provide any kind of arguments these also have to be encoded as JSON and sent in the body of a POST request. - -Please make sure to set the `Content-Type` header of your `POST` requests to `application/json` if you are sending JSON encoded data in the body of the request. +All the responses to all calls are encoded as `JSON` objects. If endpoints require the client to provide any kind of arguments these also have to be encoded as `JSON` and sent in the body of a `POST` request. Make sure to set the `Content-Type` header of your `POST` requests to `application/json` if you are sending `JSON` encoded data in the body of the request. ### Error handling -If a call fails for some reason the returned [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) will indicate that, and an object will be returned that looks like this and gives the reason for which the call errored: +If a call fails for some reason the returned [HTTP status code](https://en.wikipedia.org/wiki/List\_of\_HTTP\_status\_codes) will indicate that, and an object will be returned that looks like this and gives the reason why the call failed: ```json { - "error": "some message explaining why the call failed" -} -``` - -## Authentication - -Some API endpoints, like for example [querying referral fees](#querying-referral-fees), require clients to authenticate their requests. - -To authenticate your API request, three request headers have to be set: - -- `TS`: current UNIX timestamp (can only deviate from server time by 1 minute at most) -- `API-KEY`: your API key -- `API-HMAC`: SHA256 HMAC encoded as HEX of the following values: - - value of the `TS` header - - method of the HTTP request (e.g. `GET` or `POST`) - - request path, including the leading slash (e.g. `/referrals/query`) - - if the request method is `POST`, the body of the request - -TypeScript Node.js example: - -```typescript -import axios from 'axios'; -import { createHmac } from 'crypto'; - -const path = '/referrals/query'; - -const ts = Math.round(new Date().getTime() / 1000); -const hmac = createHmac('sha256', argv.secret) - .update(`${ts}GET${path}`) - .digest('hex'); - -try { - const res = await axios.get(`https://${argv.rest.host}:${argv.rest.port}${path}`, { - headers: { - 'TS': ts, - 'API-KEY': argv.key, - 'API-HMAC': hmac, - }, - }); - - console.log(JSON.stringify(res.data, undefined, 2)); -} catch (e) { - const error = e as any; - console.log(`${error.message}: ${JSON.stringify(error.response.data)}`); + "error": "message explaining why the call failed" } ``` -## Getting version +## Backend Version -To get the version of the deployed Boltz backed instance one has to query this API endpoint. +Returns the version of [Boltz Backend](https://github.com/BoltzExchange/boltz-backend) serving the API. A good call to get started and see if Boltz API requests and responses are working. -| URL | Response | -|----------------|-------------| -| `GET /version` | JSON object | +| URL | Response | +| -------------- | ------------- | +| `GET /version` | `JSON` object | Status Codes: -- `200 OK` +* `200 OK` Response object: -- `version`: the deployed version of the Boltz backend +* `version`: the deployed version of Boltz Backend **Examples:** @@ -85,36 +44,37 @@ Response object: ```json { - "version": "3.0.0-beta-f7f57b7-dirty" + "version":"3.2.1-7c38088" } ``` -## Getting pairs +## Supported Pairs -To work with the instance one first has to know what pairs are supported and what kind of rates, limits and fees can be expected when creating a new swap. To get that kind of information the following call is used. +In order to create a swap, one first has to know which pairs are supported and what kind of rates, limits and fees are applied when creating a new swap. The following call returns this information. -| URL | Response | -|-----------------|-------------| -| `GET /getpairs` | JSON object | +| URL | Response | +| --------------- | ------------- | +| `GET /getpairs` | `JSON` object | Status Codes: -- `200 OK` +* `200 OK` Response object: -- `info`: contains information about the configuration of the Boltz backend instance. As of writing this there is only one info status: - - `prepay.minerfee`: if the array contains this value, the instance requires a small invoice for the miner fee to be paid before the actual hold invoice of a Reverse Swap is revealed -- `warnings`: an array of strings that can indicate that some feature of Boltz might me disabled or restricted. Currently, there is only a single warning that could be in that array: - - `reverse.swaps.disabled`: means that all reverse swaps (from Lightning to the chain) are disabled -- `pairs`: an object containing of the supported pairs of that particular Bolt instance. The keys of the values are the IDs of the pairs and the values itself contain information about the trading pair: - - `rate`: the exchange rate of the pair - - `limits`: a JSON object containing the minimal and maximal amount that a swap of that pair is allowed to have. The numbers are denominated **10 \*\* -8** of the *quote currency* - - `maximalZeroConf`: the maximal amounts that will be accepted as 0-confirmation by Boltz - - `fees`: is a JSON object that has two different kinds of fees: - - `percentage`: the configured percentage fee that is charged by Boltz - - `minerFees`: are the miner fees that are expected when locking up or claiming funds. These values are absolute, denominated in **10 \*\* -8** of the currency and just estimations that are not actually enforced - - `hash`: SHA256 hash of the JSON encoded data in the pair object (in the order `rate`, `fees`, `limits`) +* `info`: contains information about special configuration parameters of the Boltz Backend deployment. As of writing this there is only one possible value: + * `prepay.minerfee`: If the array contains this value, Boltz requires a small invoice for the miner fee to be paid before the actual hold invoice of a Reverse Swap is revealed. As of writing, Boltz does _not_ require this prepayment and thus returns an empty array. +* `warnings`: an array of strings that indicate that some feature of Boltz might me disabled or restricted. An example of a warning is: + * `reverse.swaps.disabled`: Means that all reverse swaps (from Lightning to the chain) are disabled. +* `pairs`: an object containing the supported pairs. The keys of the values are the IDs of the pairs (`BTC/BTC` is a special case with mainchain bitcoin as _base asset_ and Lightning bitcoin as _quote asset_) and the values itself contain information about the pair: + * `hash`: SHA256 hash of the `JSON` encoded data in the pair object. + * `rate`: The exchange rate of the pair. + * `limits`: a `JSON` Object containing the minimal and maximal amount of the pair's swap. The numbers are denominated **10 \*\* -8** of the _quote asset._ + * `maximalZeroConf`: The maximal amounts that will be accepted without chain confirmations by Boltz. + * `fees`: A `JSON` object that contains different kinds of fees: + * `percentage`: The percentage of the "send amount" that is charged by Boltz as "Boltz Fee" for swaps from quote to base asset (e.g. Lightning -> Bitcoin). + * `percentageSwapIn`: The percentage of the "send amount" that is charged by Boltz as "Boltz Fee" for a swap from base to quote asset (e.g. Bitcoin -> Lightning). + * `minerFees`: The network fees charged for locking up and claiming funds on the chain. These values are absolute, denominated in **10 \*\* -8** of the quote asset. **Examples:** @@ -124,315 +84,279 @@ Response: ```json { - "info": [ - "prepay.minerfee" - ], + "info": [], "warnings": [], "pairs": { "BTC/BTC": { + "hash": "05d0f522ef08dd66fa0f87f167cc1380eaf7e5227e698941ecb44876e0736cb8", "rate": 1, "limits": { - "maximal": 4294967, - "minimal": 10000, + "maximal": 10000000, + "minimal": 50000, "maximalZeroConf": { - "baseAsset": 10000000, - "quoteAsset": 10000000 + "baseAsset": 0, + "quoteAsset": 0 } }, "fees": { "percentage": 0.5, + "percentageSwapIn": 0.1, "minerFees": { "baseAsset": { - "normal": 340, + "normal": 1360, "reverse": { - "claim": 276, - "lockup": 306 + "claim": 1104, + "lockup": 1224 } }, "quoteAsset": { - "normal": 340, + "normal": 1360, "reverse": { - "claim": 276, - "lockup": 306 + "claim": 1104, + "lockup": 1224 } } } - }, - "hash": "9bd7be89256a2afa5933cd1771e621558197d11cbbc98be1c5ebc2d085e34c29" + } }, - "ETH/BTC": { - "rate": 0.026357, + "L-BTC/BTC": { + "hash": "769215ae0f8cb14d250374a77de530ac2887c927dc08f8efce74f3634df03171", + "rate": 1, "limits": { - "maximal": 4294967, + "maximal": 10000000, "minimal": 10000, "maximalZeroConf": { "baseAsset": 0, - "quoteAsset": 10000000 + "quoteAsset": 0 } }, "fees": { - "percentage": 5, + "percentage": 0.25, + "percentageSwapIn": 0.1, "minerFees": { "baseAsset": { - "normal": 24924, + "normal": 147, "reverse": { - "claim": 24924, - "lockup": 46460 + "claim": 152, + "lockup": 276 } }, "quoteAsset": { - "normal": 340, + "normal": 1360, "reverse": { - "claim": 276, - "lockup": 306 + "claim": 1104, + "lockup": 1224 } } } - }, - "hash": "d0e48159d717634478574ad8263267cecd69ad5ea102889d6f6908ff67af6f26" + } } } } ``` -## Getting Lightning nodes +## Creating Normal Submarine Swaps -This endpoint allows you to query the node public keys and URIs of the Lightning nodes run by Boltz. +This section walks you through creating Normal Submarine Swaps (Chain -> Lightning). They differ slightly depending on the kind of bitcoin that are swapped, more information below. **Please note that Boltz works with 10 \*\* -8 decimals internally** and all amounts in the API endpoints follow this denomination. All requests to create swaps have the following common values in the API request: -| URL | Response | -|-----------------|-------------| -| `GET /getnodes` | JSON object | +* `type`: type of the swap to create. For Normal Submarine Swaps this is `submarine` . +* `pairId`: the pair of which the swap should be created, for more check [#supported-pairs](api.md#supported-pairs "mention") +* `orderSide`: currently we recommend using `sell` across all pairs of swap type `submarine`. The value `buy` for e.g. the `L-BTC/BTC` pair signifies a swap from mainchain Bitcoin to Liquid Lightning. As of writing, this is not supported and the backend will return `"error": "L-BTC has no lightning support"` -Status Codes: +Normal Submarine Swaps: If you already know the amount to be swapped, you should also set `invoice`. -- `200 OK` +* `invoice`: the invoice of the user that should be paid -Response object: +If the amount is **not** known yet, a **preimage hash has be specified**. The invoice that is provided later [during the lifecycle of the Submarine Swap](api.md#set-invoice) has to have the _same preimage hash_ as the one specified here. -- `nodes`: a JSON with the symbol of the chain on which the Lightning node is running as key, and a JSON object as key - - `nodeKey`: public key of the Lightning node - - `uris`: array of the URIs to which the LND node listens +* `preimageHash`: hash of a preimage that will be used for the invoice that is set later on -**Examples:** +We recommend verifing that pair data fetched previously is still accurate by additionally passing the `pairHash` argument in this call. -`GET /getnodes` +* `pairHash`: `hash` string in the pair object of [`/getpairs`](api.md#supported-pairs) -Response: +> Note: Channel creation is currently disabled! -```json -{ - "nodes": { - "BTC": { - "nodeKey": "03be597bb2c8e5ff2592b226f4433b557c34158a95699384fcadc7a2f153e7272b", - "uris": [ - "03f060953bef5b777dc77e44afa3859d022fc1a77c55138deb232ad7255e869c00@35.237.24.136:9735", - "03f060953bef5b777dc77e44afa3859d022fc1a77c55138deb232ad7255e869c00@idz7qlezif6hgmjkpmuelnsssyxea2lwan562a5gla7jmlxsl5cb2cad.onion:9735" - ] - } - } -} -``` +~~Boltz also supports opening a channel to your node before paying your invoice. To ensure that this service works as advertised **make sure to connect your Lightning node to ours** before creating the swap. You can either query the URIs of our Lightning nodes with~~ [~~`/getnodes`~~](api.md#lightning-node-info)~~, find them in the FAQ section of our website or on Lightning explorers like~~ [~~1ML~~](https://1ml.com) ~~under the query "Boltz". To let Boltz open a channel to you have to set a couple more values in the request when creating a swap:~~ -## Node statistics +* ~~`channel`: a `JSON` object that contains all the information relevant to the creation of the channel~~ + * ~~`auto`: whether Boltz should dynamically decide if a channel should be created based on whether the invoice you provided can be paid without opening a channel. More modes will be added in the future~~ + * ~~`private`: whether the channel to your node should be private~~ + * ~~`inboundLiquidity`: percentage of the channel balance that Boltz should provide as inbound liquidity for your node. The maximal value here is `50`, which means that the channel will be balanced 50/50, minimum value is 10, which means that the channel will be balanced 90 on user, 10 on Boltz side.~~ -For display purposes on our website, basic statistics about the lightning nodes are exposed in the API. +~~To find out how to enforce that the requested channel was actually opened and the invoice paid through it have a look at~~ [~~this document where we wrote down some possible solutions~~](channel-creation.md)~~.~~ -| URL | Response | -|------------------|-------------| -| `GET /nodestats` | JSON object | +| URL | Response | +| ------------------ | ------------- | +| `POST /createswap` | `JSON` object | Status Codes: -- `200 OK` +* `201 Created` +* `400 Bad Request`: if the swap could not be created. Check the `error` string in the `JSON` object of the body of the response for more information -Response object: +Response objects: -- `nodes`: a JSON with the symbol of the chain on which the Lightning node is running as key, and a JSON object as key - - `peers`: number of peers - - `channels`: number of public channels - - `oldestChannel`: UNIX timestamp of the block in which the opening transaction of the oldest channel was included - - `capacity`: sum of the capacity of all public channels +Response objects of all swaps have these value in common: -**Examples:** +* `id`: id of the newly created swap +* `timeoutBlockHeight`: base asset block height at which the swap will expire and be cancelled +* `address`: address in which the bitcoin will be locked up. For UTXO chains this is a SegWit `P2SHP2WSH` (`P2WSH` nested in a `P2SH`) for the sake of compatibility and for RSK it is the address of the contract that needs to be used -`GET /nodestats` +If a lightning invoice is set in this call, one will also find the following values in the response: -Response: +* `acceptZeroConf`: whether Boltz will accept 0-conf for this swap +* `expectedAmount`: the amount that Boltz expects to be locked on the chain -```json -{ - "nodes": { - "BTC": { - "peers": 79, - "channels": 103, - "oldestChannel": 1590772669, - "capacity": 369879555 - } - } -} -``` +### UTXO Chains +Normal Submarine Swaps from UTXO chains like Bitcoin work by deriving an address based on the preimage hash (of the invoice) and the refund public key of the user. Boltz then waits until the user sent bitcoin to the generated address. -## Get timeouts +Requests for these kind of swaps have to contain one additional parameter: -Boltz Swaps have different timeouts for each pair. This endpoint allows querying those timeouts denominated in blocks of the base and quote chain. +* `refundPublicKey`: public key of a keypair that will allow the user to refund the locked up bitcoin once the time lock is expired. This keypair has to be generated and stored by the client integrating Boltz API. -| URL | Response | -|-----------------|-------------| -| `GET /timeouts` | JSON object | +Responses also contain one additional value: -Status Codes: +* `redeemScript`: redeem script from which the `address` is derived. The redeem script can (and should!) be used to verify that the Boltz didn't try to cheat by providing an address without HTLC -- `200 OK` +In case the address is for the Liquid Network, it will be blinded by a key that is also in the response: -Response object: +* `blindingKey`: hex encoded private key with which the address was blinded + +If the invoice has been set, you will also get this value: -- `timeouts`: a JSON object with the pairs as keys and a JSON object with the timeouts as values +* `bip21`: a [BIP21 payment request](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) for the `expectedAmount` and the `address` **Examples:** -`GET /timeouts` +`POST /createswap` -Response: +Request body: ```json { - "timeouts": { - "LTC/BTC": { - "base": 160, - "quote": 40 - }, - "BTC/BTC": { - "base": 144, - "quote": 144 - }, - "LTC/LTC": { - "base": 576, - "quote": 576 - }, - "ETH/BTC": { - "base": 720, - "quote": 18 - }, - "BTC/USDT": { - "base": 18, - "quote": 720 - } - } + "type": "submarine", + "pairId": "BTC/BTC", + "orderSide": "sell", + "refundPublicKey": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGBkraVi05Eyn6slRQV5h+fX6rtpudOq0LqPEnbnbxRshMdhS56vKWawUNLkLZZ4hKsTdbJZvgTtO/rDc2WI/Gw", + "invoice": "lntb1m1pjv0dt5pp5y9dl3z50c5g6p26a86g432zdzvdlx6a565hk55a2ellz3t9f84jsdqqcqzzsxqyz5vqsp5a4k0f59u62na3fngv24nv5xjuxyf6qjnnj806se373h4gt9fmejq9qyyssqpeh42yy72pqzfwdfehvuru9s735vrgg324lxdp9gg8w6m379w8ajd3sxyy6f0qqfqa6vhk5k4pqfz6nys3u5xf68wcjyjygykn7za6cqf6flce" } ``` +Response: -## Getting contracts - -To query the addresses of the contracts Boltz uses on account based chains this endpoint must be queried. - -| URL | Response | -|---------------------|-------------| -| `GET /getcontracts` | JSON object | - -Status Codes: - -- `200 OK` - -Response object: - -- `ethereum`: a JSON object that contains all relevant Ethereum addresses - - `network`: JSON object that contains information about the Ethereum network the backend is running on - - `chainId`: id of the Ethereum the backend in running on - - `name`: if the Ethereum network of the backend is public, this property will be set to its name. Else this value stays `undefined` - - `swapContracts`: JSON object with the keys `EtherSwap` and `ERC20Swap` and the corresponding addresses as values - - `tokens`: JSON object with the ticker symbol of the token as key and its address as value +```json +{ + "id": "E63LC4", + "bip21": "bitcoin:2NBBYeBZgY64nJKiibnGokwrBBPjoQeMzyx?amount=0.0010054&label=Send%20to%20BTC%20lightning", + "address": "2NBBYeBZgY64nJKiibnGokwrBBPjoQeMzyx", + "redeemScript": "a9148f8d01a3e1a794024fa78bd9c81d5ae9bb1c56d287632102bba4fbfe50ea8caf880cb367f7b0083c7e91c2bc2808c817823bd36385e3a376670319b125b17503aaaae268ac", + "acceptZeroConf": false, + "expectedAmount": 100540, + "timeoutBlockHeight": 2470169 +} +``` -**Examples:** +_Submarine Swap that includes the_ [_creation of a new channel_](channel-creation.md)_:_ -`GET /getcontracts` +`POST /createswap` -Response: +Request body: ```json { - "ethereum": { - "network": { - "chainId": 1337 - }, - "swapContracts": { - "EtherSwap": "0x76562e81C099cdFfbF6cCB664543817028552634", - "ERC20Swap": "0xD104195e630A2E26D33c8B215710E940Ca041351" - }, - "tokens": { - "USDT": "0x52926360A75EB50A9B242E748f094eCd73193036" - } + "type": "submarine", + "pairId": "BTC/BTC", + "orderSide": "sell", + "refundPublicKey": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGBkraVi05Eyn6slRQV5h+fX6rtpudOq0LqPEnbnbxRshMdhS56vKWawUNLkLZZ4hKsTdbJZvgTtO/rDc2WI/Gw", + "invoice": "lntb10m1pjv0w7jpp5upaf56avdlkjv9h602m9heaa004reuc36yjf2hwzcv3tk0kjaekqdqqcqzzsxqyz5vqsp5klkwplct9kuzp8whrmjvqxqjhnga907aa953xdeaqypa8mn6chtq9qyyssqlywerx9cdqxukf640kphw2rtz6uamtc0g94h7jt99jpspjxn653h6gn30a6ejndh4xuxuf2gxn2sndgqhvs33s5ayg70z4p4f7n267gp4tytl0", + "channel": { + "auto": true, + "private": false, + "inboundLiquidity": 30 } } ``` -## Getting fee estimations +Response: -Boltz provides an API endpoint that returns fee estimations for all chains that are configured on that instance. These fee estimations are *not* enforced by Boltz and are just a recommendation. +```json +{ + "id": "e1Qtxa", + "bip21": "bitcoin:2Muq74He81w8Ts4n3zhPFd1JZbuWC62czux?amount=0.0100234&label=Send%20to%20BTC%20lightning", + "address": "2Muq74He81w8Ts4n3zhPFd1JZbuWC62czux", + "redeemScript": "a91479674970eaa348958799f6fc41ef379d00f9060f8763210385ad894cdd1f27f4c88ef403100420eed6cc006965a3a58e277cb05c6f469d6667031ab125b17503aaaae268ac", + "acceptZeroConf": false, + "expectedAmount": 1002340, + "timeoutBlockHeight": 2470170 +} +``` -For UTXO based chains like Bitcoin it is important to mention that if 0-conf wants to be used with normal swaps, the lockup transaction has to have at least 80% of the recommended `sat/vbyte` value. One can read more about the what and why in the [0-confirmation docs](0-confirmation.md). +### EVM Chains (Coming Soon!) -If the instance supports Ether or ERC20 tokens, only `ETH` will be in the response. This value is for the Ethereum chain and not the Ether asset and denominated in GWEI. +~~Swaps from account-based EVM chains like RSK do not require a new address for every swap. `/createswap` takes the details of the swap (like lightning invoice and pair) and Boltz waits until the user locked e.g. rBTC in the contract. The addresses of those contracts can be queried with~~ [~~`/getcontracts`~~](api.md#swap-contracts-coming-soon) ~~and the address of the contract that needs to be used for the swap is also returned in the response of this request.~~ -| URL | Response | -|-------------------------|-------------| -| `GET /getfeeestimation` | JSON object | +~~The request does not require any additional values.~~ -Status Codes: +~~But the response has one additional value:~~ -- `200 OK` +* ~~`claimAddress`: which is e.g. the RSK address of Boltz. It is specified in the`lock` function of the swap contract~~ -Response object: +~~**Examples:**~~ -This endpoint returns a JSON object of which each key is the symbol of a chain and each value the estimated fee for that chain denominated in `sat/vbyte` or `GWEI`. +~~`POST /createswap`~~ -**Examples:** +~~Request body:~~ -`GET /getfeeestimation` +```json +{ + "type": "submarine", + "pairId": "RBTC/BTC", + "orderSide": "buy", + "invoice": "lnbcrt1m1p0c26rvpp5hctw8zukj00tsxay5436y43qxc5gwvdc6k9zcxnce4zer7p5a4eqdqqcqzpgsp59mwcr4cj6wq68qj6pzyjtq2j89vnpumsejdmhw5uy4yukq3vd64s9qy9qsq2537ph4kt4xryq27g5juc27v2tkx9y90hpweyqluku9rt5zfexfj6n2fqcgy7g8xx72fklr6r7qul27jd0jzvssvrhxmwth7w4lrq7sqgyv0m7" +} +``` -Response: +~~Response:~~ ```json { - "BTC": 34, - "LTC": 2, - "ETH": 10 + "id": "7PSEtx", + "address": "0xD104195e630A2E26D33c8B215710E940Ca041351", + "claimAddress": "0xe20fC13bad486fEB7F0C87Cad42bC74aAc319684", + "acceptZeroConf": false, + "expectedAmount": 1387707329, + "timeoutBlockHeight": 2006 } ``` -## Querying transactions - -The Boltz API also allows for querying raw transactions for all supported UTXO based chains. Irrespective of whether the transactions are still in the mempool or already included in a block; Boltz should find them either way. But it should be noted that unlike SPV and Neutrino servers, Boltz doesn't provide any kind of proof that the transaction was included in a block. +### Swap Rates -Requests querying for transactions have to be `POST` and contain two arguments in its JSON encoded body: +When sending chain bitcoin, before setting the invoice of a Normal Submarine Swap, you'll need to use this endpoint to figure out what the amount of the invoice you set should be. Send a `POST` request with a `JSON` encoded body with this value: -- `currency`: which chain should be queried for the transaction -- `transactionId`: the id of the transaction that should be queried +* `id`: id of the Submarine Swap -| URL | Response | -|------------------------|-------------| -| `POST /gettransaction` | JSON object | +| URL | Response | +| ----------------- | ------------- | +| `POST /swaprates` | `JSON` object | Status Codes: -- `200 OK` -- `400 Bad Request`: if an argument wasn't provided or the transaction can't be found +* `200 OK` +* `400 Bad Request`: if the invoice amount could not be calculated. Check the `error` string in the `JSON` object of the body of the response for more information. A common case is where the user did not lock up chain bitcoin yet, which is a requirement in order to calculate an invoice amount: `"error": "no coins were locked up yet"` Response object: -- `transactionHex`: the requested transaction encoded in hex +* `invoiceAmount`: amount of the invoice that should be set with [`/setinvoice`](api.md#set-invoice) **Examples:** -`POST /gettransaction` - Request body: ```json { - "currency": "BTC", - "transactionId": "52ff6682b0bff109e6c6d97de6b6d075f7241c9ac364e02de6315281e423d816" + "id": "BY8asG" } ``` @@ -440,43 +364,53 @@ Response: ```json { - "transactionHex": "02000000000101f7ddc247aad2c1e91b2495cf6814aa183b46785cf21f44f43a3c3419c09d377201000000171600142a805e4cfaa6fb79360917a5b0b9c5fcb0dfe6e9ffffffff02938601000000000017a9141137c50104d0814e8663ded75b43ddaa7b9d192b87e8cc96000000000017a9148f6df517d00e650d8c5e6bfa0986b775b256609e870247304402202e8a8572ce3cb232a7b48483bdc280feba7f9cf8c163ac2df091e54dfcf90bb6022042ba2b3e4d89220b3b39b52a444dff2010b22144099aaa348d83301f2ae456be01210341720559e7375a409b03e814415a6c15fc142c5a9e78a83831ff6fe4706d352900000000" + "invoiceAmount": 15713393 } ``` -## Querying lockup Transactions +### Setting an Invoice -Requests querying the lockup transactions on UTXO based chains of Submarine Swaps have to be `POST` and contain one argument in its JSON encoded body: +In case the amount to be swapped is not known when creating a Normal Submarine Swap, the invoice can be set afterwards; even if the chain bitcoin were sent already. Please keep in mind that the invoice **has to have the same preimage hash** that was specified when creating the swap. Although the invoice can be changed after setting it initially, this endpoint will only work if Boltz did not try to pay the initial invoice yet. Requests to this endpoint have to be `POST` and should have the following values in its `JSON` encoded body: -- `id`: id of the Submarine Swap +* `id`: id of the swap for which the invoice should be set +* `invoice`: invoice of the user that should be paid -| URL | Response | -|----------------------------|-------------| -| `POST /getswaptransaction` | JSON object | +| URL | Response | +| ------------------ | ------------- | +| `POST /setinvoice` | `JSON` object | Status Codes: -- `200 OK` -- `400 Bad Request`: if an argument wasn't provided, or the Submarine Swap can't be found +* `200 OK` +* `400 Bad Request`: if the invoice could not be set. Check the `error` string in the `JSON` object of the body of the response for more information -Response object: +Response objects: -- `transactionHex`: the lockup transaction of the Submarine Swap encoded in hex -- `timeoutBlockHeight`: block height at which the HTLC in the lockup transaction will time out +What is returned when the invoice is set depends on the status of the Submarine Swap. If no funds were sent (status [`swap.created`](lifecycle.md#normal-submarine-swaps)) the endpoint will return a `JSON` object with these values: -If the HTLC has not timed out yet, there will be an additional value in the response: +* `acceptZeroConf`: whether Boltz will accept 0-conf for this swap +* `expectedAmount`: the amount that Boltz expects you to lock in the chain HTLC +* `bip21`: a [BIP21 payment request](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) for the `expectedAmount` of bitcoin and the `address` (only set when swapping from UTXO based chains) + +If chain bitcoin were sent already (status [`transaction.mempool`](lifecycle.md#normal-submarine-swaps) or [`transaction.confirmed`](lifecycle.md#normal-submarine-swaps)) the endpoint will return an empty `JSON` object, signifying success. + +In case this endpoint is called again after an invoice was set and Boltz tried to pay it already: -- `timeoutEta`: UNIX timestamp at which the HTLC is expected to time out +* `error`: error message explaining that Boltz tried to pay the invoice already and that it cannot be changed anymore +* `invoice`: the invoice that was set and that will be used for the swap **Examples:** -`POST /getswaptransaction` +If _no_ bitcoin were sent yet: + +`POST /setinvoice` Request body: ```json { - "id": "KR8XaB" + "id": "UwHIPg", + "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" } ``` @@ -484,69 +418,41 @@ Response: ```json { - "transactionHex": "020000000001015bf3fe03071edae971276831963d45821ce6bc95c567fd7832bee3b1848254ba0000000000feffffff02b82a75e80000000017a914ca9b26af0865c2a59f0d6c41ede68f03264a52398700e1f5050000000017a914d2271732308baf018a1c2c751a3afb197f2a2e7e870247304402200206ae10cd66267caea1c6e0fca0275924a85fa377572f599304c1abb6a3a97302204335eed108151048de7ba56fd644352831e3d453b412547d8b762f4e96ee1e310121035b6440fe45a8bf7c1d9d238fa39a128ee78b58df73377bfeb1d6d752849714c800000000", - "timeoutBlockHeight": 252, - "timeoutEta": 1586353245 + "acceptZeroConf": true, + "expectedAmount": 1359564, + "bip21": "bitcoin:QNaGS7WM31xANXQCbmrhXfnxUjxiGFpFwM?amount=0.01359564&label=Submarine%20Swap%20to%20BTC" } ``` -`POST /getswaptransaction` +If bitcoin _were sent_ already: + +`POST /setinvoice` Request body: ```json { - "id": "KR8XaB" + "id": "UwHIPg", + "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" } ``` Response: ```json -{ - "transactionHex": "020000000001015bf3fe03071edae971276831963d45821ce6bc95c567fd7832bee3b1848254ba0000000000feffffff02b82a75e80000000017a914ca9b26af0865c2a59f0d6c41ede68f03264a52398700e1f5050000000017a914d2271732308baf018a1c2c751a3afb197f2a2e7e870247304402200206ae10cd66267caea1c6e0fca0275924a85fa377572f599304c1abb6a3a97302204335eed108151048de7ba56fd644352831e3d453b412547d8b762f4e96ee1e310121035b6440fe45a8bf7c1d9d238fa39a128ee78b58df73377bfeb1d6d752849714c800000000", - "timeoutBlockHeight": 252 -} +{} ``` -## Broadcasting transactions - -This endpoint is really similar to the one for querying transactions (and it works only on UTXO based chains too). But instead of getting existing transactions this one will broadcast new ones to the network. Also it returns the id of the broacasted transaction. - -Requests broadcasting transactions have to be `POST` and contain two arguments in its JSON encoded body: - -- `currency`: to which network the transaction should be broadcasted -- `transactionHex`: the HEX encoded transaction itself - -| URL | Response | -|------------------------------|-------------| -| `POST /broadcasttransaction` | JSON object | - -Status Codes: - -- `200 OK` -- `400 Bad Request`: if an argument wasn't provided or the node that should broadcast the transaction returns an error - -Response object: - -- `transactionId`: the id of the transaction that was broadcasted +If the invoice was previously set and Boltz tried to pay it already: -There is one special case when trying to broadcast a refund transaction for a Submarine Swap that has not timed out yet: the backend will not only return `error` in the JSON encoded response but also some information alongside that error to make your life a little bit easier: - -- `error`: the reason for which the broadcasting failed. In this special case always: `non-mandatory-script-verify-flag (Locktime requirement not satisfied) (code 64)` -- `timeoutEta`: UNIX timestamp at which the HTLC is expected to time out -- `timeoutBlockHeight`: block height at which the HTLC in the lockup transaction will time out - -**Examples:** - -`POST /broadcasttransaction` +`POST /setinvoice` Request body: ```json { - "currency": "BTC", - "transactionHex": "02000000000101f7ddc247aad2c1e91b2495cf6814aa183b46785cf21f44f43a3c3419c09d377201000000171600142a805e4cfaa6fb79360917a5b0b9c5fcb0dfe6e9ffffffff02938601000000000017a9141137c50104d0814e8663ded75b43ddaa7b9d192b87e8cc96000000000017a9148f6df517d00e650d8c5e6bfa0986b775b256609e870247304402202e8a8572ce3cb232a7b48483bdc280feba7f9cf8c163ac2df091e54dfcf90bb6022042ba2b3e4d89220b3b39b52a444dff2010b22144099aaa348d83301f2ae456be01210341720559e7375a409b03e814415a6c15fc142c5a9e78a83831ff6fe4706d352900000000" + "id": "UwHIPg", + "invoice": "lnbcrt100u1p0gv8hjpp5j0vs0te6wykahrp3aammm46m73n2afzk6a87ezfp3p58qpcpu4wqdqqcqzpgsp5j6wue634lac577xnupy8auvq7n9062vshvvc6xszq4jt5q9phhzq9qy9qsqhs7zrs98tu669xz7w0gqy96g5pvs9p6lssmyseg7a92kpjlzramk8khyzkd8x4nl2zasekmwt45z6pe78rk032lkmshjdnesw2vukwgqtglt89" } ``` @@ -554,72 +460,84 @@ Response: ```json { - "transactionId": "52ff6682b0bff109e6c6d97de6b6d075f7241c9ac364e02de6315281e423d816" + "error": "lightning payment in progress already", + "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" } ``` -*Special case when broadcasting a refund for a Submarine Swap that has not timed out yet:* - -`POST /broadcasttransaction` +## Creating Reverse Submarine Swaps -Request body: +This section walks you creating Reverse Submarine Swaps (Lightning -> Chain) and is similar to creating Normal Submarine Swaps. In the same way, requests and responses change slightly depending on the kind of bitcoin involved in the swap. Keep in mind, **Boltz uses 10 \*\* -8 as denomination** for responses on the API. -```json -{ - "currency": "BTC", - "transactionHex": "0100000000010113a19f721bc15b17a63700a7bf0056b7640b2c80239577f7ee95618baa34958f0100000023220020e1088f54c6d46e861bf4c5590bdff35c6f277b10e4e2787e1a5df23f1e540a3dfdffffff01bcdff5050000000016001486590ca595782212ce4fe0a4be8855f55f7f288603483045022100c142b9616659ba1728c254d8e275a304dc31c9139f005f9a97938cb1606c370e0220686d4e6166a7adab916f9af823c2f173aa9bd7f47a581909bda95881e1c00e07010064a9146aad1375552e58e9d4281a331caf271d0d160e3c8763210396ed47336687c51bc7e2bd32d0fc7a377d33c888f02a0647a7f1156761614a0d6702c401b1752103ffb18860cbe08060bd93a17abe4b436c46d0ee5b43fd0c24ba5bd65d6f42beb568ac00000000" -} -``` +All requests bodies extend from: -Response: +* `type`: type of the swap to create. For Reverse Submarine Swaps this is `reversesubmarine`. +* `pairId`: the pair of which the swap should be created, for more check [#supported-pairs](api.md#supported-pairs "mention") +* `orderSide`: currently we recommend using `buy` across all pairs of swap type `reversesubmarine`. The value `sell` for e.g. the `L-BTC/BTC` pair signifies a swap from mainchain Bitcoin to Lightning on Liquid. As of writing, this is not supported and the backend will return `"error": "L-BTC has no lightning support"` +* `preimageHash`: the SHA256 hash of a preimage that was generated by the client. The size of that preimage has to be 32 bytes or claiming will fail -```json -{ - "timeoutEta": 1586374147, - "timeoutBlockHeight": 452, - "error": "non-mandatory-script-verify-flag (Locktime requirement not satisfied) (code 64)" -} -``` +There are two ways to set the amount of a Reverse Swap. Either by specifying the amount of the invoice Boltz will generate: -## Getting status of a Swap +* `invoiceAmount`: amount of the invoice that will be generated by Boltz -**Before being able to handle the status events of this method it is recommended to read: [Swap lifecycle](lifecycle.md)** +Or by setting the amount that will be locked in the chain HTLC. That amount is _not_ what you will actually receive because of transaction fees required to claim the HTLC. But those can be approximated easily in advance and when overestimating a little, a quick confirmation of the claim transaction can be ensured. -To query the status of a swap one can use this endpoint which returns a JSON object containing the status of the swap. All the possible status events are documented [here](lifecycle.md). +* `onchainAmount`: amount Boltz will lock in the chain HTLC -Requests querying the status of a swap have to be `POST` and contain a single value in its JSON encoded body: +We recommend verifing that pair data fetched previously is still accurate by additionally passing the `pairHash` argument in this call. -- `id`: the id of the swap of which the status should be queried +* `pairHash`: `hash` string in the pair object of [`/getpairs`](api.md#supported-pairs) -| URL | Response | -|--------------------|-------------| -| `POST /swapstatus` | JSON object | +| URL | Response | +| ------------------ | ------------- | +| `POST /createswap` | `JSON` object | Status Codes: -- `200 OK` -- `404 Not Found`: if the swap with the provided id couldn't be found -- `400 Bad Request`: if the `id` argument wasn't provided +* `201 Created` +* `400 Bad Request`: if the swap could not be created. Check the `error` string in the `JSON` object of the body of the response for more information -Response object: +The `JSON` object in the response extends from: + +* `id`: id of the newly created swap +* `lockupAddress`: address derived from the `redeemScript` or contract in which Boltz will lock up bitcoin +* `invoice`: hold invoice that needs to be paid before Boltz locks up bitcoin +* `timeoutBlockHeight`: block height at which the Reverse Swap will be cancelled + +In case the invoice amount was specified, the amount that will be locked in the chain HTLC is also returned: + +* `onchainAmount`: amount of chain bitcoin that will be locked by Boltz + +Boltz backend also supports a different protocol that requires an invoice for miner fees to be paid before the actual hold `invoice` of the Reverse Submarine Swap. If that protocol is enabled, the response object will also contain a `minerFeeInvoice`. Once the `minerFeeInvoice` is paid, Boltz will send the event `minerfee.paid` and when the actual hold `invoice` is paid, the chain bitcoin will be sent. + +### UTXO based chains + +The request has to contain one additional value: + +* `claimPublicKey`: public key of a keypair that will allow the user to claim the locked up bitcoin with the preimage. This keypair has to be generated and stored by the client integrating Boltz API. + +And so has the response: -- `status`: status of the swap -- `transaction`: in case of a reverse swap the lockup transaction details are not in the response of the call which creates the swap. Therefore, the events `transaction.mempool` and `transaction.confirmed` contain it - - `id`: id of the lockup transaction - - `hex`: hex encoded lockup transaction (only set for transactions on UTXO based chains) - - `eta`: if the status is `transaction.mempool`, this value is the estimated time of arrival (ETA) in blocks of when the transaction will be confirmed (only set for transactions on UTXO based chains) -- `zeroConfRejected`: set to `true` for Swaps with the status `transaction.mempool` and a lockup transaction that is not eligible for 0-conf -- `failureReason`: set if the status indicates that the Swap failed and the status itself would be ambiguous +* `redeemScript`: redeem script from which the lockup address was derived. The redeem script can (and should!) be used to verify that Boltz didn't try to cheat by creating an address without a HTLC + +In case the lockup address is on the Liquid Network, it will be blinded by a key that is also in the response: + +* `blindingKey`: hex encoded private key with which the address was blinded **Examples:** -`POST /swapstatus` +`POST /createswap` Request body: ```json { - "id": "Asnj2Y" + "type": "reversesubmarine", + "pairId": "L-BTC/BTC", + "orderSide": "buy", + "invoiceAmount": 1000000, + "preimageHash": "51a05b15e66ecd12bf6b1b62a678e63add0185bc5f41d2cd013611f7a4b6703f", + "claimPublicKey": "03b76c1fe14bab50e52a026f35287fda75b9304bcf311ee85b4d32482400a436f5" } ``` @@ -627,21 +545,155 @@ Response: ```json { - "status": "invoice.paid" + "id": "v3CfMa", + "invoice": "lntb10m1pjvsy8ppp52xs9k90xdmx390mtrd32v78x8twsrpdutaqa9ngpxcgl0f9kwqlsdpz2djkuepqw3hjqnpdgf2yxgrpv3j8yetnwvcqz95xqrrsssp5hzcjq972f9cl8c6u3zechepm65hjceaqvlzye6kc23qkz5rhva6q9qyyssq4kkw9fwjq7n9cm4j3ajj2a92ka0zyeg3sxppfy932c62pnsqkw7nhvg9rrxztszw37wqtal4cchw2f4s09qe48pngsl9euv7wjlz93qqrfx60s", + "blindingKey": "897034f717beb12a3c2b7ae8c08c5c4def7bc7cfb6efa3713c617f28d90d1419", + "redeemScript": "8201208763a914be1abd8e8d7ef7e64a9c6e1e2f498f3a92e078a2882103b76c1fe14bab50e52a026f35287fda75b9304bcf311ee85b4d32482400a436f5677503dbf40eb175210330fd4cfd53b5c20886415c1b67d2daa87bce2761b9be009e9d1f9eec4419ba5968ac", + "lockupAddress": "tlq1qqdd0v79wcqnpvujf5mfp88d5cz8rynk0awr6m84ca8pzn39kwagsh4z204s9d5sww3cxckd47wjxlqwl3u6tgdqfa877txqt9m8wgk22qwyp5yzxaf40", + "timeoutBlockHeight": 980187, + "onchainAmount": 995724 } ``` -`POST /swapstatus` +_In case the prepay miner fee protocol is enabled:_ Request body: ```json { - "id": "ryUK9G" + "type": "reversesubmarine", + "pairId": "BTC/BTC", + "orderSide": "buy", + "claimPublicKey": "0391fbaf549578fd7c2cb26b216441825bd780d85dba1f3d706e2f206587e96266", + "invoiceAmount": 100000, + "preimageHash": "2215034def003b63b2717fccd4ce8259f4807a39318c14e2bdd42639ca989a45" } ``` -Response: +Response body: + +```json +{ + "id": "mVSKyF", + "invoice": "lnbcrt996940n1p0dhjr3pp5yg2sxn00qqak8vn30lxdfn5zt86gq73exxxpfc4a6snrnj5cnfzsdql2djkuepqw3hjqsj5gvsxzerywfjhxuccqzy0sp5hjcvwl2glrq9n3vzm8072cdruz3hhz70edml8g0u76gryve6np4q9qy9qsqzw5w8ulxjgrg478hz4enjrw0a9tedl8s3n879xqh3mhn0pxrvajrz9qnnsr58twx4a30gk57d4fykm7x3v2vcamw7k4ny9fkpwl65vcpw8v5em", + "redeemScript": "8201208763a914fb75ff5dc4272c2da33d744615905f54b62de41588210391fbaf549578fd7c2cb26b216441825bd780d85dba1f3d706e2f206587e962666775028e01b1752102c22801bd7dd3a6afb780671c1c983fcd91fa46826eadd82e325e7e13bb348a9768ac", + "lockupAddress": "bcrt1qweryu6nk8gn5lj8ar5kjdy476wynheszg0lumu6jx83l2v6f435stlel03", + "onchainAmount": 98694, + "timeoutBlockHeight": 398, + "minerFeeInvoice": "lnbcrt3060n1p0dhjr3pp5sk2u4rt0z8rrl6jj62d6szqvsdejj8kjcxa8tdt4dau5rtyskj6qdp4f45kuetjypnx2efqvehhygznwashqgr5dusyy4zrypskgerjv4ehxcqzpgsp5qtsm5vfy9yq8kjpthla67jagmcxnj529pm3edk94npf6fekq2sxq9qy9qsqmun0z8ed4kp9dhp7lthvzdrx3ngmjs32smx6l4hvyyktv92mf348aftgrwf44sl94ewywr3sw8dc4acy63yamxxpjtd4pkkr2uw2h5gpqc3d3y" +} +``` + +### EVM Chains (Coming Soon!) + +~~Requests to create swaps for Reverse Submarine Swaps from account-based EVM chains like RSK have to contain one additional value:~~ + +* ~~`claimAddress`: address from which the bitcoin will be claimed~~ + +~~The response also has one more property:~~ + +* ~~`refundAddress`: the address of Boltz which is specified as refund address when it is locking up funds~~ + +~~Also, Boltz offers an optional protocol called EVM prepay miner fee that allows the user to pay an additional lightning invoice to pay for gas on the EVM chain to claim funds. In this process, Boltz sends some e.g. rBTC to the `claimAddress` in the lockup process in case the user's `claimAddress` does not have enough rBTC to pay gas to claim the funds. To use that protocol set the following property in the request body to `true`.~~ + +* ~~`prepayMinerFee`: if the prepay miner fee protocol should be used for the Reverse Swap~~ + +~~When the EVM prepay miner fee protocol is used the response will contain two more values. One is the amount of rBTC that will be sent to `claimAddress` in the lockup process. The other is an invoice for the rBTC sent. Only when both invoices are paid the chain bitcoin will get locked.~~ + +* ~~`prepayMinerFeeAmount`: amount of e.g. rBTC that will be sent to the `claimAddress` with the lockup transaction from Boltz~~ +* ~~`minerFeeInvoice`: invoice that pays for the rBTC sent in the lockup process~~ + +~~**Examples:**~~ + +~~`POST /createswap`~~ + +~~Request body:~~ + +```json +{ + "type": "reversesubmarine", + "pairId": "rBTC/BTC", + "orderSide": "sell", + "claimAddress": "0x88532974EC20559608681A53F4Ac8C34dd5e2804", + "invoiceAmount": 100000, + "preimageHash": "295b93a766959d607861ab7b7a6bf9e178e7c69c3cc4ca715065dfe9d6eea351" +} +``` + +~~Response body:~~ + +```json +{ + "id": "1H6eCx", + "invoice": "lnbcrt1m1p0ega6epp599de8fmxjkwkq7rp4dah56leu9uw035u8nzv5u2svh07n4hw5dgsdpq2djkuepqw3hjq42ng32zqctyv3ex2umncqzphsp5gxshtrx3y0mt3llm3537qqy0ylf722hykv2zm777dwap9e60glfq9qy9qsqa93q725njkt9dupu9cddtchwcmyg7zsltrw8gcyzsc4tv74ss26y00z7tutrqks8wgh8s286ayy2tmrul0q0ysvxjzv793ylcdr553gqjhgny2", + "refundAddress": "0xe20fC13bad486fEB7F0C87Cad42bC74aAc319684", + "lockupAddress": "0xD104195e630A2E26D33c8B215710E940Ca041351", + "onchainAmount": 1210297576, + "timeoutBlockHeight": 2006 +} +``` + +## Swap Status + +_Before handling status events of this method it is recommended to read:_ [_Swap Types & States_](lifecycle.md) + +To query the status of a swap one can use this endpoint which returns a `JSON` object containing the status of the swap. Possible states and status events are documented in the section [Swap Types & States](lifecycle.md)_._ + +Requests querying the status of a swap have to be `POST` and contain a single value in its `JSON` encoded body: + +* `id`: the id of the swap of which the status should be queried + +| URL | Response | +| ------------------ | ------------- | +| `POST /swapstatus` | `JSON` object | + +Status Codes: + +* `200 OK` +* `404 Not Found`: if the swap with the provided id couldn't be found +* `400 Bad Request`: if the `id` argument wasn't provided + +Response object: + +* `status`: status of the swap, e.g. `transaction.mempool` & `transaction.claimed` for successful Normal Submarine Swaps and `transaction.mempool` and `transaction.confirmed` for successful Reverse Submarine Swaps +* `transaction`: for Reverse Submarine Swaps, this field contains lockup transaction details in the states`transaction.mempool` and `transaction.confirmed` + * `id`: id of the lockup transaction + * `hex`: hex encoded lockup transaction (only set for transactions on UTXO chains) + * `eta`: if the status is `transaction.mempool`, this value is the estimated time of arrival (ETA) in blocks of when the transaction will be confirmed. Only set for transactions on UTXO chains. +* `zeroConfRejected`: set to `true` for Swaps with the status `transaction.mempool` and a lockup transaction that is not eligible for [0-conf](0-confirmation.md) +* `failureReason`: set when it's necessary to further clarify the failure reason + +**Examples:** + +`POST /swapstatus` + +Request body: + +```json +{ + "id": "Asnj2Y" +} +``` + +Response: + +```json +{ + "status": "invoice.paid" +} +``` + +`POST /swapstatus` + +Request body: + +```json +{ + "id": "ryUK9G" +} +``` + +Response: ```json { @@ -673,21 +725,21 @@ Response: } ``` -## Streaming status updates of a Swap +## Swap Status Stream -To not having to query the [`/swapstatus`](#getting-status-of-a-swap) endpoint regularly in order to always have the lastet swap status there is a seperate endpoint for streaming swap status updates via [Server-Side events](https://www.w3schools.com/html/html5_serversentevents.asp). +To avoid querying the [`/swapstatus`](api.md#swap-status) endpoint regularly to get the latest swap status, this endpoint streams swap status updates via [Server-Side Events](https://www.w3schools.com/html/html5\_serversentevents.asp). -Requests to this enpoint have to provide the required `id` parameter via an URL parameter because all requests have to be of the method `GET`. +Requests to this endpoint have to provide the required swap `id` parameter via an URL parameter because all requests have to be of the method `GET`. -Every event in the Server-Side stream has data that is encoded exactly like the JSON object of the [`/swapstatus`](#getting-status-of-a-swap) endpoint. Please have a look at the examples below for a reference implementation in JavaScript of hanlding the stream. +Every event in the Server-Side stream has data that is encoded exactly like the `JSON` object of the `/swapstatus` endpoint. Please have a look at the examples below for a reference implementation in JavaScript of handling the stream. | URL | Response | -|-------------------------|--------------------------| +| ----------------------- | ------------------------ | | `GET /streamswapstatus` | Server-Side event stream | **Examples:** -Server-Side event streams have to be handled different from normal HTTP responses. Below is a sample implementation in JavaScript and also what a raw response of a Server-Side event stream looks like. +Server-Side event streams have to be handled differently from regular HTTP responses. Below is a sample implementation in JavaScript and also what a raw response of a Server-Side event stream looks like. Sample implementation in JavaScript: @@ -709,200 +761,165 @@ data: {"status":"transaction.mempool"} data: {"status":"invoice.paid"} ``` -## Querying referral fees +## Swap Timeouts -Boltz partners can request a referral key to get a percentage of the fees earned from Swaps through their integration. To query for their referrals, they can send an [authenticated](#authentication) request to this endpoint. +Boltz Swaps have different timeouts for each pair. This endpoint allows querying those timeouts denominated in blocks of the base and quote chain. -| URL | Response | -|------------------------|-------------| -| `GET /referrals/query` | JSON object | +| URL | Response | +| --------------- | ------------- | +| `GET /timeouts` | `JSON` object | Status Codes: -- `200 OK` -- `401 Unauthorized`: missing or invalid request authentication +* `200 OK` Response object: -The response of a valid request is grouped by year, month and referral key. The amounts are denominated in 10 \*\* -8. +* `timeouts`: a `JSON` object with the pairs as keys and a `JSON` object with the timeouts as values **Examples:** -`GET /referrals/query` +`GET /timeouts` Response: ```json { - "2021": { - "9": { - "cliTest": { - "BTC": 60 + "timeouts": { + "BTC/BTC": { + "base": { + "reverse": 144, + "swapMinimal": 144, + "swapMaximal": 288 + }, + "quote": { + "reverse": 144, + "swapMinimal": 144, + "swapMaximal": 288 + } + }, + "L-BTC/BTC": { + "base": { + "reverse": 1440, + "swapMinimal": 1440, + "swapMaximal": 2880 + }, + "quote": { + "reverse": 144, + "swapMinimal": 144, + "swapMaximal": 288 } } } } ``` -## Creating Swaps - -To create a swap from onchain coins to lightning ones just a single request has to be sent. This `POST` request slightly deviates depending on the kind of currencies that are swapped. You can find further information on the differences between swapping from UTXO based chains and Ethereum underneath. **Please note that Boltz works with 10 \*\* -8 decimals internally** and all amounts in the API endpoints have this denomination regardless of the decimals, regardless of the swapped coin or token. - -Also, all kinds of requests to create Swaps have common values in the API request: +## Swap Contracts (Coming Soon!) -- `type`: type of the swap to create; always `submarine` for normal swaps -- `pairId`: the pair on which the swap should be created -- `orderSide`: either `buy` or `sell` depending on what the user wants +~~To query the addresses of contracts used by Boltz for swaps on EVM chains like~~ [~~RSK~~](https://rootstock.io/)~~, the following endpoint can be queried:~~ -If you already know the amount you want to swap you should also set `invoice`. - -- `invoice`: the invoice of the user that should be paid - -If the amount is **not** known, a **preimage hash should be specified**. The invoice that is [set during the lifecycle of the Submarine Swap](#setting-the-invoice-of-a-swap) has to have the same preimage hash as the one specified when creating the swap. - -- `preimageHash`: hash of a preimage that will be used for the invoice that is set later on - -In case the client wants to verify the pair data fetched by it is still accurate, the `pairHash` argument can be passed. - -- `pairHash`: `hash` string in the pair object of [`/getpairs`](#getting-pairs) - -Boltz also supports opening a channel to your node before paying your invoice. To ensure that this service works as advertised **make sure to connect your Lightning node to ours** before creating the swap. You can either query the URIs of our Lightning nodes with [`/getnodes`](#getting-lightning-nodes), find them in the FAQ section of our website or on Lightning explorers like [1ML](https://1ml.com) under the query "Boltz". To let Boltz open a channel to you have to set a couple more values in the request when creating a swap: - -- `channel`: a JSON object that contains all the information relevant to the creation of the channel - - `auto`: whether Boltz should dynamically decide if a channel should be created based on whether the invoice you provided can be paid without opening a channel. More modes will be added in the future - - `private`: whether the channel to your node should be private - - `inboundLiquidity`: percentage of the channel balance that Boltz should provide as inbound liquidity for your node. The maximal value here is `50`, which means that the channel will be perfectly balanced 50/50 - -To find out how to enforce that the requested channel was actually opened and the invoice paid through it have a look at [this document where we wrote down some possible solutions](channel-creation.md). - -| URL | Response | -|--------------------|-------------| -| `POST /createswap` | JSON object | - -Status Codes: +| URL | Response | +| ------------------- | ------------- | +| `GET /getcontracts` | `JSON` object | -- `201 Created` -- `400 Bad Request`: if the swap could not be created. Check the `error` string in the JSON object of the body of the response for more information +~~Status Codes:~~ -Response objects: +* ~~`200 OK`~~ -You will always have these values in the response object: +~~Response object:~~ -- `id`: id of the freshly created swap -- `timeoutBlockHeight`: block height at which the swap will be cancelled -- `address`: address in which the coins will be locked up. For UTXO based chains this is a SegWit P2SHP2WSH (P2WSH nested in a P2SH) for the sake of compatibility and for Ethereum it is the address of the contract that needs to be used +* ~~`rsk`: a `JSON` object that contains all relevant RSK addresses~~ + * ~~`network`: `JSON` object that contains information about the network~~ + * ~~`chainId`: id of the RSK chain~~ + * ~~`name`: if the RSK network of the backend is public, this property will be set to its name. Else this value stays `undefined`.~~ + * ~~`swapContracts`: `JSON` object containing swap contract addresses as values~~ + * ~~`tokens`: `JSON` object with the ticker symbol of the supported token as key and its address as value~~ -If you set the invoice you will also have these values in the response: +~~**Examples:**~~ -- `acceptZeroConf`: whether Boltz will accept 0-conf for this swap -- `expectedAmount`: the amount that Boltz expects you to lock in the onchain HTLC +~~`GET /getcontracts`~~ -### UTXO based chains +~~Response:~~ -Swaps from UTXO based chains like Bitcoin work by deriving an address based on the preimage hash of the invoice and the refund public key of the user and waiting until the user sends coins to that generated address. +```json +{ + "rsk": { + "network": { + "chainId": 1337 + }, + "swapContracts": { + "rBTCSwap": "0x0", + "TokenSwap": "0x0" + }, + "tokens": { + } + } +} +``` -Requests have to contain one additional parameter: +## Fee Estimations -- `refundPublicKey`: public key of a keypair that will allow the user to refund the locked up coins once the time lock is expired +Boltz provides an API endpoint that returns fee estimations for all supported chains. These fee estimations are _not_ enforced by Boltz and merely represent a recommendation. -Responses also contain one additional value: +For UTXO chains like Bitcoin it is important to mention that if 0-conf is accepted by Boltz for a particular pair and to be used with Normal Submarine Swaps, the lockup transaction has to have at least 80% of the recommended `sat/vbyte` value. One can read more about the what and why in the [0-conf docs](0-confirmation.md). -- `redeemScript`: redeem script from which the `address` is derived. The redeem script can and should be used to verify that the Boltz instance didn't try to cheat by providing an address without a HTLC +| URL | Response | +| ----------------------- | ------------- | +| `GET /getfeeestimation` | `JSON` object | -In case the address is for the Liquid network, it will be blinded by a key that is also in the response: +Status Codes: -- `blindingKey`: hex encoded private key with which the address was blinded +* `200 OK` -If the invoice has been set in the request, you will also get this value: +Response object: -- `bip21`: a [BIP21 payment request](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) for the `expectedAmount` of coins and the `address` +This endpoint returns a `JSON` object of which each key is the symbol of a chain and each value the estimated fee for that chain denominated in `sat/vbyte` for UTXO chains like Bitcoin or `GWEI` for EVM chains like RSK. **Examples:** -`POST /createswap` - -Request body: - -```json -{ - "type": "submarine", - "pairId": "LTC/BTC", - "orderSide": "sell", - "refundPublicKey": "03b76c1fe14bab50e52a026f35287fda75b9304bcf311ee85b4d32482400a436f5", - "invoice": "lnbcrt100u1pw54eudpp5e42ls0apxfm2790aesc92v5kppkr5dluvv0545v6zr593498s8zsdqqcqzpgpyaz550xmqkr6v5x8cn3qxyxmuxp7xa28xlr7qhkxlde3xm8xjyyqqurx5nq8tdeejvm4jnuw468lxjtnfj8v49hsg8tkhjz9haj65sps8xdv0" -} -``` +`GET /getfeeestimation` Response: ```json { - "id": "SWxaMe", - "acceptZeroConf": true, - "expectedAmount": 1359564, - "timeoutBlockHeight": 120, - "address": "QNaGS7WM31xANXQCbmrhXfnxUjxiGFpFwM", - "bip21": "litecoin:QNaGS7WM31xANXQCbmrhXfnxUjxiGFpFwM?amount=0.01359564&label=Submarine%20Swap%20to%20BTC", - "redeemScript": "a9140b8d541b172265d880331130438e69661cc5303487632102ea2e82321fd8cfa4efc3615fe3cb2675d75f0964d033d2853c37fbd99ced363d670178b17542a9142f7150b969c9c9fb9094a187f8fb41d617a65e20876300670171b1752102e317e5607e757e9c4448fe458876d7e361222d2cbee33ece9e3a7b2e2359be4d68ac68ac" + "BTC": 16, + "L-BTC": 0.11 } ``` -*Submarine Swap that includes the creation of a new channel:* - -`POST /createswap` +## Raw Transactions -Request body: +Boltz API also allows for querying raw transactions of all supported UTXO chains, irrespective of whether the transactions are still in the mempool or already included in a block. Note, that Boltz does _not_ provide any kind of cryptographic proof that the transaction was included in a block. Also this call is primarily kept for backward compatibility with older integrations, it is _not_ needed to construct transactions as the response of [`/swapstatus`](api.md#swap-status) provides all necessary info. -```json -{ - "type": "submarine", - "pairId": "LTC/BTC", - "orderSide": "sell", - "refundPublicKey": "03b76c1fe14bab50e52a026f35287fda75b9304bcf311ee85b4d32482400a436f5", - "invoice": "lnbcrt100u1pw54eudpp5e42ls0apxfm2790aesc92v5kppkr5dluvv0545v6zr593498s8zsdqqcqzpgpyaz550xmqkr6v5x8cn3qxyxmuxp7xa28xlr7qhkxlde3xm8xjyyqqurx5nq8tdeejvm4jnuw468lxjtnfj8v49hsg8tkhjz9haj65sps8xdv0", - "channel": { - "private": true, - "inboundLiquidity": 30 - } -} -``` - -Response: +Requests querying for transactions have to be `POST` and contain two arguments in its JSON encoded body: -```json -{ - "id": "SIqEW9", - "acceptZeroConf": true, - "expectedAmount": 1005340, - "timeoutBlockHeight": 252, - "address": "2NBFGsAUUa9qgoMFPLrmAquCLv2qunUPDAU", - "bip21": "bitcoin:2NBFGsAUUa9qgoMFPLrmAquCLv2qunUPDAU?amount=0.0100534&label=Send%20to%20BTC%20lightning", - "redeemScript": "a9141384278c2be432627fd934e0f13b3e0c3edbbe458763210250035e2afeb9b2213d01f8374afabff4e4bdfee71909c3cd28ba37571d7a289e6702fc00b1752103e25b3f3bb7f9978410d52b4c763e3c8fe6d43cf462e91138c5b0f61b92c93d7068ac" -} -``` +* `currency`: which chain should be queried for the transaction +* `transactionId`: the id of the transaction that should be queried -### Ethereum +| URL | Response | +| ---------------------- | ------------- | +| `POST /gettransaction` | `JSON` object | -Swaps from the Ethereum do not need a new address for every Swap. They work by registering the details of the Swap (like invoice and pair) in our database and waiting until the user locks either Ether in the `EtherSwap` or ERC20 tokens in the `ERC20Swap` contract. The addresses of those contracts can be queried with [`/getcontracts`](http://localhost:8000/api/#getting-contracts) and the address of the contract that needs to be used for the Swap is also in the response of the API request. +Status Codes: -The request does not require any additional values. +* `200 OK` +* `400 Bad Request`: if an argument wasn't provided or the transaction can't be found -But the response has one more value: +Response object: -- `claimAddress`: which is the Ethereum address of Boltz. It has to be specified in the `lock` function of the swap contract +* `transactionHex`: the requested transaction encoded in hex **Examples:** -`POST /createswap` +`POST /gettransaction` Request body: ```json { - "type": "submarine", - "pairId": "BTC/USDT", - "orderSide": "buy", - "invoice": "lnbcrt1m1p0c26rvpp5hctw8zukj00tsxay5436y43qxc5gwvdc6k9zcxnce4zer7p5a4eqdqqcqzpgsp59mwcr4cj6wq68qj6pzyjtq2j89vnpumsejdmhw5uy4yukq3vd64s9qy9qsq2537ph4kt4xryq27g5juc27v2tkx9y90hpweyqluku9rt5zfexfj6n2fqcgy7g8xx72fklr6r7qul27jd0jzvssvrhxmwth7w4lrq7sqgyv0m7" + "currency": "BTC", + "transactionId": "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" } ``` @@ -910,41 +927,43 @@ Response: ```json { - "id": "7PSEtx", - "address": "0xD104195e630A2E26D33c8B215710E940Ca041351", - "claimAddress": "0xe20fC13bad486fEB7F0C87Cad42bC74aAc319684", - "acceptZeroConf": false, - "expectedAmount": 1387707329, - "timeoutBlockHeight": 2006 + "transactionHex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000" } ``` -## Getting Swap rates +## Lockup Transactions -When sending onchain coins before setting the invoice of a Submarine Swap, you need to use this endpoint to figure out what the amount of the invoice you set should be. Send a `POST` request with a JSON encoded body with this value: +The following endpoint can be used to query the user's lockup transaction of a Normal Submarine Swap on UTXO chains. The request has to be `POST` and contain the following argument in the `JSON` encoded body: -- `id`: id of the Submarine Swap +* `id`: id of the Submarine Swap -| URL | Response | -|-------------------|-------------| -| `POST /swaprates` | JSON object | +| URL | Response | +| -------------------------- | ------------- | +| `POST /getswaptransaction` | `JSON` object | Status Codes: -- `200 OK` -- `400 Bad Request`: if the invoice amount could not be calculated. Check the `error` string in the JSON object of the body of the response for more information +* `200 OK` +* `400 Bad Request`: if an argument wasn't provided, or the Submarine Swap can't be found Response object: -- `invoiceAmount`: amount of the invoice that should be set with [/setinvoice](#setting-the-invoice-of-a-swap) +* `transactionHex`: the lockup transaction of the Normal Submarine Swap encoded in hex +* `timeoutBlockHeight`: block height at which the HTLC in the lockup transaction will time out + +If the HTLC has not timed out yet, there will be an additional value in the response: + +* `timeoutEta`: UNIX timestamp at which the HTLC is expected to time out **Examples:** +`POST /getswaptransaction` + Request body: ```json { - "id": "BY8asG" + "id": "KR8XaB" } ``` @@ -952,53 +971,52 @@ Response: ```json { - "invoiceAmount": 15713393 + "transactionHex": "020000000001015bf3fe03071edae971276831963d45821ce6bc95c567fd7832bee3b1848254ba0000000000feffffff02b82a75e80000000017a914ca9b26af0865c2a59f0d6c41ede68f03264a52398700e1f5050000000017a914d2271732308baf018a1c2c751a3afb197f2a2e7e870247304402200206ae10cd66267caea1c6e0fca0275924a85fa377572f599304c1abb6a3a97302204335eed108151048de7ba56fd644352831e3d453b412547d8b762f4e96ee1e310121035b6440fe45a8bf7c1d9d238fa39a128ee78b58df73377bfeb1d6d752849714c800000000", + "timeoutBlockHeight": 252, + "timeoutEta": 1586353245 } ``` -## Setting the invoice of a Swap - -In case the amount to be swapped is not known when creating the Submarine Swap, the invoice can be set afterward and even if the onchain coins were sent already. Please keep in mind that the invoice of a Submarine Swap **has to have the same preimage hash** that was specified when creating the Submarine Swap. Although the invoice can be changed after setting it initially, this enpoint will only work if Boltz did not try to pay the initial invoice yet. Requests to this endpoint have to be `POST` and should have the following values in its JSON encoded body: - -- `id`: id of the Submarine Swap for which the invoice should be set -- `invoice`: invoice of the user that should be paid +This call works for Normal Submarine Swaps only. If used for Reverse Submarine Swaps, the response will be: -| URL | Response | -|--------------------|-------------| -| `POST /setinvoice` | JSON object | +```json +{ + "error": "could not find swap with id: CR8XaB" +} +``` -Status Codes: +## Broadcasting transactions -- `200 OK` -- `400 Bad Request`: if the invoice could not be set. Check the `error` string in the JSON object of the body of the response for more information +This endpoint is used to broadcast transactions on UTXO chains. It is similar to [`/gettransaction`](api.md#raw-transactions) but instead of getting the hex representation of existing transactions on the chain, this call broadcasts _new_ transactions to the network. It is mainly intended to be used to broadcast refund transactions on user's behalf. It returns the id of the broacasted transaction,which can be used to verify that the refund transaction was broadcasted successfully. -Response objects: +Requests broadcasting transactions have to be `POST` and contain two arguments in the `JSON` encoded body: -What is returned when the invoice is set depends on the status of the Submarine Swap. If no coins were sent already (status [`swap.created`](lifecycle.md#normal-submarine-swaps)) the endpoint will return a JSON object with these values: +* `currency`: to which network the transaction should be broadcasted +* `transactionHex`: the HEX encoded transaction itself -- `acceptZeroConf`: whether Boltz will accept 0-conf for this swap -- `expectedAmount`: the amount that Boltz expects you to lock in the onchain HTLC -- `bip21`: a [BIP21 payment request](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) for the `expectedAmount` of coins and the `address` (only set when swapping from UTXO based chains) +| URL | Response | +| ---------------------------- | ------------- | +| `POST /broadcasttransaction` | `JSON` object | -If onchain coins were sent already (status [`transaction.mempool`](lifecycle.md#normal-submarine-swaps) or [``transaction.confirmed``](lifecycle.md#normal-submarine-swaps)) the endpoint will return an empty JSON object. +Status Codes: -In case this endpoint is called again after an invoice was set and Boltz tried to pay it already: +* `200 OK` +* `400 Bad Request`: if an argument wasn't provided or the node that should broadcast the transaction returns an error -- `error`: error message explaining that Boltz tried to pay the invoice already and that it cannot be changed anymore -- `invoice`: the invoice that set by the client and will be used for the Submarine Swap +Response object: -**Examples:** +* `transactionId`: the id of the transaction that was broadcasted -*If no coins were sent yet:* +**Example:** -`POST /setinvoice` +`POST /broadcasttransaction` Request body: ```json { - "id": "UwHIPg", - "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" + "currency": "BTC", + "transactionHex": "02000000000101f7ddc247aad2c1e91b2495cf6814aa183b46785cf21f44f43a3c3419c09d377201000000171600142a805e4cfaa6fb79360917a5b0b9c5fcb0dfe6e9ffffffff02938601000000000017a9141137c50104d0814e8663ded75b43ddaa7b9d192b87e8cc96000000000017a9148f6df517d00e650d8c5e6bfa0986b775b256609e870247304402202e8a8572ce3cb232a7b48483bdc280feba7f9cf8c163ac2df091e54dfcf90bb6022042ba2b3e4d89220b3b39b52a444dff2010b22144099aaa348d83301f2ae456be01210341720559e7375a409b03e814415a6c15fc142c5a9e78a83831ff6fe4706d352900000000" } ``` @@ -1006,41 +1024,26 @@ Response: ```json { - "acceptZeroConf": true, - "expectedAmount": 1359564, - "bip21": "litecoin:QNaGS7WM31xANXQCbmrhXfnxUjxiGFpFwM?amount=0.01359564&label=Submarine%20Swap%20to%20BTC" -} -``` - -*If coins were sent to the lockup address already:* - -`POST /setinvoice` - -Request body: - -```json -{ - "id": "UwHIPg", - "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" + "transactionId": "52ff6682b0bff109e6c6d97de6b6d075f7241c9ac364e02de6315281e423d816" } ``` -Response: +There is one special case: when trying to broadcast a refund transaction for a swap that has not timed out yet, the backend will return some additional information in addition to the `error` in the `JSON` encoded response: -```json -{} -``` +* `error`: the reason for which the broadcasting failed. In this special case always: `non-mandatory-script-verify-flag (Locktime requirement not satisfied) (code 64)` +* `timeoutEta`: UNIX timestamp at which the HTLC is expected to time out +* `timeoutBlockHeight`: block height at which the HTLC in the lockup transaction will time out -*If the invoice was set and Boltz tried to pay it already:* +**Example:** -`POST /setinvoice` +`POST /broadcasttransaction` Request body: ```json { - "id": "UwHIPg", - "invoice": "lnbcrt100u1p0gv8hjpp5j0vs0te6wykahrp3aammm46m73n2afzk6a87ezfp3p58qpcpu4wqdqqcqzpgsp5j6wue634lac577xnupy8auvq7n9062vshvvc6xszq4jt5q9phhzq9qy9qsqhs7zrs98tu669xz7w0gqy96g5pvs9p6lssmyseg7a92kpjlzramk8khyzkd8x4nl2zasekmwt45z6pe78rk032lkmshjdnesw2vukwgqtglt89" + "currency": "BTC", + "transactionHex": "0100000000010113a19f721bc15b17a63700a7bf0056b7640b2c80239577f7ee95618baa34958f0100000023220020e1088f54c6d46e861bf4c5590bdff35c6f277b10e4e2787e1a5df23f1e540a3dfdffffff01bcdff5050000000016001486590ca595782212ce4fe0a4be8855f55f7f288603483045022100c142b9616659ba1728c254d8e275a304dc31c9139f005f9a97938cb1606c370e0220686d4e6166a7adab916f9af823c2f173aa9bd7f47a581909bda95881e1c00e07010064a9146aad1375552e58e9d4281a331caf271d0d160e3c8763210396ed47336687c51bc7e2bd32d0fc7a377d33c888f02a0647a7f1156761614a0d6702c401b1752103ffb18860cbe08060bd93a17abe4b436c46d0ee5b43fd0c24ba5bd65d6f42beb568ac00000000" } ``` @@ -1048,174 +1051,164 @@ Response: ```json { - "error": "lightning payment in progress already", - "invoice": "lnbcrt1m1p08epqjpp5yvv222x7te9asyzuhmjym083lwqpp5vlem09ewfeufyrp6f76w2sdql2djkuepqw3hjqnz5gvsxzerywfjhxuccqzpgsp5u6kxgf9daf64ptvl2ht74m6duc2neywx3ecvwxs07vf7egw5dy5s9qy9qsqakms0e7ww46q9cq2fa2ymrcx6nucfknjalkm5w4ywvjpfxdp5ya82drvdvxhqzzt2ysysh5u7rellzjse37fng3vsqafuwwz3kv4ykcquy8k29" + "timeoutEta": 1586374147, + "timeoutBlockHeight": 452, + "error": "non-mandatory-script-verify-flag (Locktime requirement not satisfied) (code 64)" } ``` -## Creating Reverse Swaps - -Creating reverse swaps (lightning to onchain coins) is pretty similar to creating normal ones. Similarly, the requests and responses also slightly change based on the coin or token you are swapping from. Keep in mind that **Boltz uses 10 \*\* -8 as denomination** in the API. - -All requests bodies extend from: - -- `type`: type of the swap to create; always `reversesubmarine` for reverse swaps -- `pairId`: the pair on which the swap should be created -- `orderSide`: either `buy` or `sell` depending on what the user wants -- `preimageHash`: the SHA256 hash of a preimage that was generated locally by the client. The size of that preimage has to be 32 bytes or none of locked the coins can get claimed - -There are two ways to set the amount of a Reverse Swap. Either by specifying the amount of the invoice Boltz will generate: - -- `invoiceAmount`: amount of the invoice that will be generated by Boltz - -Or by setting the amount that will be locked in the onchain HTLC. That amount is *not* what you will actually receive because of the transaction fees required to claim the HTLC. But those can be approximated easily in advance and when overestimating a little, a quick confirmation of the claim transaction can be ensured. - -- `onchainAmount`: amount Boltz will lock in the onchain HTLC +## Authentication -In case the client wants to verify the pair data fetched by it is still accurate, the `pairHash` argument can be passed. +Boltz API does not require any sort of authentication to perform swaps. However, some API endpoints like [querying referral fees](api.md#querying-referral-fees) for members of our partner program, do. -- `pairHash`: `hash` string in the pair object of [`/getpairs`](#getting-pairs) +To authenticate your API request, three request headers have to be set: -| URL | Response | -|--------------------|-------------| -| `POST /createswap` | JSON object | +* `TS`: current UNIX timestamp (can only deviate from server time by 1 minute at most) +* `API-KEY`: your API key +* `API-HMAC`: SHA256 HMAC encoded as HEX (lower case letters!) of the following values: + * value of the `TS` header + * method of the HTTP request (e.g. `GET` or `POST`) + * request path, including the leading slash (e.g. `/referrals/query`) + * if the request method is `POST`, the body of the request -Status Codes: - -- `201 Created` -- `400 Bad Request`: if the swap could not be created. Check the `error` string in the JSON object of the body of the response for more information +TypeScript Node.js example: -The JSON object in the response extends from: +```typescript +import axios from 'axios'; +import { createHmac } from 'crypto'; -- `id`: id of the freshly created swap -- `lockupAddress`: address derived from the `redeemScript` or Ethereum contract to which Boltz will lockup coins -- `invoice`: hold invoice that needs to be paid before Boltz locks up coins -- `timeoutBlockHeight`: block height at which the Reverse Swap will be cancelled +const path = '/referrals/query'; -In case the invoice amount was specified, the amount that will be locked in the onchain HTLC is also returned: +const ts = Math.round(new Date().getTime() / 1000); +const hmac = createHmac('sha256', argv.secret) + .update(`${ts}GET${path}`) + .digest('hex'); -- `onchainAmount`: amount of onchain coins that will be locked by Boltz +try { + const res = await axios.get(`https://${argv.rest.host}:${argv.rest.port}${path}`, { + headers: { + 'TS': ts, + 'API-KEY': argv.key, + 'API-HMAC': hmac, + }, + }); -The Boltz backend also supports a different Reverse Swap protocol that requires an invoice for the miner fees to be paid before the actual hold `invoice` of the Reverse Swap. If that protocol is enabled, the response object will also contain `minerFeeInvoice`. Once that `minerFeeInvoice` is paid, Boltz will send the event `minerfee.paid` and when the actual hold `invoice` is paid, the onchain coins will be sent. + console.log(JSON.stringify(res.data, undefined, 2)); +} catch (e) { + const error = e as any; + console.log(`${error.message}: ${JSON.stringify(error.response.data)}`); +} +``` -### UTXO based chains +## Querying referral fees -The request has to contain one additional value: +Members of the Boltz partner program can request a referral key ([hi@bol.tz](mailto:hi@bol.tz)) to get a percentage of the fees earned from Swaps through their integration. To query for their referrals, they can send an [authenticated](api.md#authentication) request to this endpoint. -- `claimPublicKey`: public key of a keypair that will allow the user to claim the locked up coins with the preimage +| URL | Response | +| ---------------------- | ------------- | +| `GET /referrals/query` | `JSON` object | -And so has the response: +Status Codes: -- `redeemScript`: redeem script from which the lockup address was derived. The redeem script can and should be used to verify that the Boltz instance didn't try to cheat by creating an address without a HTLC +* `200 OK` +* `401 Unauthorized`: missing or invalid request authentication -In case the lockup address is for the Liquid network, it will be blinded by a key that is also in the response: +Response object: -- `blindingKey`: hex encoded private key with which the address was blinded +The response of a valid request is grouped by year, month and referral key. **Examples:** -`POST /createswap` +`GET /referrals/query` -Request body: +Response: ```json { - "type": "reversesubmarine", - "pairId": "LTC/BTC", - "orderSide": "buy", - "invoiceAmount": 1000000, - "preimageHash": "51a05b15e66ecd12bf6b1b62a678e63add0185bc5f41d2cd013611f7a4b6704f", - "claimPublicKey": "03b76c1fe14bab50e52a026f35287fda75b9304bcf311ee85b4d32482400a436f5" + "2021": { + "9": { + "cliTest": { + "BTC": 60 + } + } + } } ``` -Response: +## Lightning Node Info -```json -{ - "id": "AgRip5", - "invoice": "lnbcrt1m1pwcuv4hpp5d5ydjvllqn9l9lxqxkjrmead28p4h8c7mhykygwcw39cfkn4y9hqdql2fjhvetjwdjjq5mhv9czqar0ypp9gsccqzpggtrxt78s655f4cfysav46rpv20u320ctswy5gx04xqvq3qjqn8a9vvkhgzeyjzs2dx9g90ge7jr9u8n42n8htf09spkudks8skds67cqklcf7k", - "redeemScript": "a914382c733f81adfd13010d2dd72da83d019cf4f13787632103e25b3f3bb7f9978410d52b4c763e3c8fe6d43cf462e91138c5b0f61b92c93d70670178b17521036721e5267bb2c4741fa1da1835dbe579ad296395c13ff954bfdbf17474d2a2ab68ac", - "onchainAmount": 99194, - "timeoutBlockHeight": 120, - "lockupAddress": "bcrt1qxelh2k86skcncmzmm6059az0n0h02d7pvhylgvdevh59u0t8rl5qycus9p" -} -``` +This endpoint allows you to query info like public keys and URIs of the lightning nodes operated by Boltz. -*In case the prepay miner fee protocol is enabled:* +| URL | Response | +| --------------- | ------------- | +| `GET /getnodes` | `JSON` object | -Request body: +Status Codes: -```json -{ - "type": "reversesubmarine", - "pairId": "BTC/BTC", - "orderSide": "buy", - "claimPublicKey": "0391fbaf549578fd7c2cb26b216441825bd780d85dba1f3d706e2f206587e96266", - "invoiceAmount": 100000, - "preimageHash": "2215034def003b63b2717fccd4ce8259f4807a39318c14e2bdd42639ca989a45" -} -``` +* `200 OK` -Response body: +Response object: + +* `nodes`: a `JSON` with the symbol of the chain on which the Lightning node is running as key, and a `JSON` object as key + * `nodeKey`: public key of the lightning node + * `uris`: array of the URIs on which the lightning node is reachable + +**Examples:** + +`GET /getnodes` + +Response: ```json { - "id": "mVSKyF", - "invoice": "lnbcrt996940n1p0dhjr3pp5yg2sxn00qqak8vn30lxdfn5zt86gq73exxxpfc4a6snrnj5cnfzsdql2djkuepqw3hjqsj5gvsxzerywfjhxuccqzy0sp5hjcvwl2glrq9n3vzm8072cdruz3hhz70edml8g0u76gryve6np4q9qy9qsqzw5w8ulxjgrg478hz4enjrw0a9tedl8s3n879xqh3mhn0pxrvajrz9qnnsr58twx4a30gk57d4fykm7x3v2vcamw7k4ny9fkpwl65vcpw8v5em", - "redeemScript": "8201208763a914fb75ff5dc4272c2da33d744615905f54b62de41588210391fbaf549578fd7c2cb26b216441825bd780d85dba1f3d706e2f206587e962666775028e01b1752102c22801bd7dd3a6afb780671c1c983fcd91fa46826eadd82e325e7e13bb348a9768ac", - "lockupAddress": "bcrt1qweryu6nk8gn5lj8ar5kjdy476wynheszg0lumu6jx83l2v6f435stlel03", - "onchainAmount": 98694, - "timeoutBlockHeight": 398, - "minerFeeInvoice": "lnbcrt3060n1p0dhjr3pp5sk2u4rt0z8rrl6jj62d6szqvsdejj8kjcxa8tdt4dau5rtyskj6qdp4f45kuetjypnx2efqvehhygznwashqgr5dusyy4zrypskgerjv4ehxcqzpgsp5qtsm5vfy9yq8kjpthla67jagmcxnj529pm3edk94npf6fekq2sxq9qy9qsqmun0z8ed4kp9dhp7lthvzdrx3ngmjs32smx6l4hvyyktv92mf348aftgrwf44sl94ewywr3sw8dc4acy63yamxxpjtd4pkkr2uw2h5gpqc3d3y" + "nodes": { + "BTC": { + "uris": [ + "026165850492521f4ac8abd9bd8088123446d126f648ca35e60f88177dc149ceb2@45.86.229.190:9735", + "026165850492521f4ac8abd9bd8088123446d126f648ca35e60f88177dc149ceb2@d7kak4gpnbamm3b4ufq54aatgm3alhx3jwmu6kyy2bgjaauinkipz3id.onion:9735" + ], + "nodeKey": "026165850492521f4ac8abd9bd8088123446d126f648ca35e60f88177dc149ceb2" + } + } } ``` -### Ethereum +## Lightning Node Statistics -The request has to contain one additional value: - -- `claimAddress`: address from which the coins will be claimed - -The response also has one more property: +For display purposes on our website, basic statistics about our lightning nodes are exposed via the following endpoint: -- `refundAddress`: the address of Boltz which is specified as refund address when it is locking coins +| URL | Response | +| ---------------- | ------------- | +| `GET /nodestats` | `JSON` object | -Also, Boltz offers an optional protocol called Ethereum prepay miner fee to send some Ether to the `claimAddress` in the lockup process. That is useful in cases the `claimAddress` does not have the Ether required to claim the coins already. To use that protocol set the following property in the request body to `true`. +Status Codes: -- `prepayMinerFee`: if the Ethereum prepay miner fee protocol should be used for the Reverse Swap +* `200 OK` -When the Ethereum prepay miner fee protocol is used the response will contain two more values. One is the amount of Ether that will be sent to `claimAddress` in the lockup process. The other is an invoice for the Ether sent. Only when both invoices are paid the onchain coins will get locked. +Response object: -- `prepayMinerFeeAmount`: amount of Ether that will be sent to the `claimAddress` with the lockup transaction from Boltz -- `minerFeeInvoice`: invoice that pays for the Ether sent in the lockup process +* `nodes`: a `JSON` with the symbol of the chain on which the Lightning node is running as key, and a `JSON` object as key + * `peers`: number of peers + * `channels`: number of public channels + * `oldestChannel`: UNIX timestamp of the block in which the opening transaction of the oldest channel was included + * `capacity`: sum of the capacity of all public channels **Examples:** -`POST /createswap` +`GET /nodestats` -Request body: +Response: ```json { - "type": "reversesubmarine", - "pairId": "BTC/USDT", - "orderSide": "sell", - "claimAddress": "0x88532974EC20559608681A53F4Ac8C34dd5e2804", - "invoiceAmount": 100000, - "preimageHash": "295b93a766959d607861ab7b7a6bf9e178e7c69c3cc4ca715065dfe9d6eea351" + "nodes": { + "BTC": { + "peers": 79, + "channels": 103, + "oldestChannel": 1590772669, + "capacity": 369879555 + } + } } ``` -Response body: - -```json -{ - "id": "1H6eCx", - "invoice": "lnbcrt1m1p0ega6epp599de8fmxjkwkq7rp4dah56leu9uw035u8nzv5u2svh07n4hw5dgsdpq2djkuepqw3hjq42ng32zqctyv3ex2umncqzphsp5gxshtrx3y0mt3llm3537qqy0ylf722hykv2zm777dwap9e60glfq9qy9qsqa93q725njkt9dupu9cddtchwcmyg7zsltrw8gcyzsc4tv74ss26y00z7tutrqks8wgh8s286ayy2tmrul0q0ysvxjzv793ylcdr553gqjhgny2", - "refundAddress": "0xe20fC13bad486fEB7F0C87Cad42bC74aAc319684", - "lockupAddress": "0xD104195e630A2E26D33c8B215710E940Ca041351", - "onchainAmount": 1210297576, - "timeoutBlockHeight": 2006 -} -``` diff --git a/docs/channel-creation.md b/docs/channel-creation.md index 11b7eaba..74b990f1 100644 --- a/docs/channel-creation.md +++ b/docs/channel-creation.md @@ -1,17 +1,24 @@ -# Channel Creation Docs +--- +description: >- + Normal Submarine Swaps can be configured to create a channel to your node + before paying the invoice. This document elaborates how this works and how to + enforce the channel opening. +--- -The Boltz Submarine Swaps can be configured to create a channel to your node before paying the invoice. This document elaborates on the way we do this and how you can enforce that the requested channel is actually opened. +# โœจ Channel Creation + +> Note: Channel Creation is currently disabled on Boltz ## Enforcing a Channel Creation -As of writing this, no Lightning implementation does support setting the channel through which an invoice should be paid or even specifying that an invoice has to be paid through a new channel to a specific node. Therefore you will have to get creative if you want to enforce that the channel Boltz agreed to open is really created. +As of writing, no Lightning implementation supports enforcing invoice payment through a new channel natively. However, the following solutions exist: -### External Daemon +### CLN - Plugin -One way to enforce that the invoice is paid through a freshly created channel with the requested properties and balances is by using [hold invoices](https://wiki.ion.radar.tech/tech/research/hodl-invoice) in combination with an external daemon. Such a daemon should have all the information required to enforce the channel creation. This is the hold invoice that should be paid, the preimage of said hold invoice and the properties of the channel that should be created. If the invoice is paid through a new channel with the aspired properties, the daemon should settle the invoice. +One way is to incorporate a logic similar to the one of the external daemon described below directly into the Lightning implementation. This can be done by modifying the source code of the client or by creating a plugin. We provide a [Core Lightning](https://github.com/ElementsProject/lightning) plugin for this use case. The full source code of the plugin can be found in [this repository](https://github.com/BoltzExchange/channel-creation-plugin). -Such a daemon could also utilize the [ChannelAcceptor of LND](https://api.lightning.community/#channelacceptor) to prevent channels with properties other than the requested ones being opened. +### LND - External Daemon -### Modifying the Lightning Client +Another way to enforce that the invoice is paid through a newly created channel with the requested properties and balances is by using [hold invoices](https://bitcoinops.org/en/topics/hold-invoices/) in combination with an external daemon. Such a daemon should have all the information required to enforce the channel creation. This is the hold invoice that should be paid, the preimage of said hold invoice and the properties of the channel that should be created. If the invoice is paid through a new channel with the aspired properties, the daemon should settle the invoice. -Another way is incorporating a logic similar to the one of the external daemon directly into the Lightning implementation. This can be done by modifying the source code of the client or by creating a plugin. We have built a [c-lightning](https://github.com/ElementsProject/lightning) plugin for this exact use case. The full source code for this plugin can be found in [this repository](https://github.com/BoltzExchange/channel-creation-plugin). +Such a daemon could also utilize the [ChannelAcceptor of LND](https://lightning.engineering/api-docs/api/lnd/lightning/channel-acceptor) to prevent channels with properties other than the requested ones being opened. diff --git a/docs/deployment.md b/docs/deployment.md index 7e734b4f..09814c6a 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,20 +1,25 @@ -# Deployment of the Boltz Backend +--- +description: >- + Deploying Boltz backend has to be done with great care since it will have full + control over the Lightning Node it is connected to. With great power comes + great responsibility. +--- -Deploying the Boltz backend has to be done with great care since it will have full control over the Lightning Node it is connected to. *With great power comes great responsibility.* +# ๐Ÿšข Deployment of Boltz Backend Prerequisites: -* The latest Node.js LTS release (`v18.16.1` as of writing this) -* `rsync` (needed to compile the TypeScript code) +* The latest [node.js lts and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed. We recommend using [nvm](https://github.com/nvm-sh/nvm#install--update-script) to manage npm installs: `nvm install --lts` +* [rsync](https://github.com/WayneD/rsync) (needed to compile the `TypeScript` code) -The Boltz backend requires a synced Bitcoin Core or Litecoin Core instance to connect to the Bitcoin or Litecoin chain. These nodes need to: +Boltz Backend requires a synced Bitcoin Core Instance to connect to the Bitcoin mainchain. Similarly, Elements Core to connect to the Liquid sidechain etc. Bitcoin Core must: -* Have the transaction index enabled `txindex=1` -* Enable ZeroMQ streams for raw blocks and raw transactions (`zmqpubrawblock=tcp://:` and `zmqpubrawtx=tcp://:`) +* Have the transaction index enabled: `txindex=1` +* Enable ZeroMQ streams for raw blocks and raw transactions: (`zmqpubrawblock=tcp://:` and `zmqpubrawtx=tcp://:`) -If the Bitcoin or Litecoin chain should also support Lightning, an [LND node](https://github.com/LightningNetwork/lnd) has to be running on the same chain. The LND node does not need to be configured in any special way but has to support `invoicesrpc`. This can be achieved by using an official release binary from the LND repository or by compiling LND with `-tags="invoicesrpc"`. +Boltz requires a [LND](https://github.com/LightningNetwork/lnd) or [CLN](https://github.com/ElementsProject/lightning/) node running on Bitcoin to be present. For LND, no special configuration is needed, all [official release binaries](https://github.com/lightningnetwork/lnd/releases) are compatible. -## Configuration +## Config Sample ```toml configpath = "/home/boltz/.boltz/boltz.conf" @@ -34,7 +39,7 @@ loglevel = "debug" # - true: P2WSH swapwitnessaddress = false -# Enables the prepay minerfee Reverse Swap procotol +# Enables the prepay minerfee Reverse Submarine Swap procotol # If this value is "true", an invoice for the miner fee has to be paid # before hold invoice of the Revese Swap prepayminerfee = false @@ -58,7 +63,7 @@ keypath = "/home/boltz/.boltz/tls.key" [rates] interval = 1 -# The Boltz Backend allows for backing up the LND channel backups and +# Boltz Backend allows for backing up LND channel backups and # the database to a Google Cloud Storage Bucket [backup] email = "" @@ -67,8 +72,8 @@ bucketname = "" # Cron interval at which a new backup should be uploaded. The default value is daily interval = "0 0 * * *" -# The Boltz backend supports sending messages to Discord after successful and failed -# Swaps and if the wallet or channel balance is underneath a configurable threshold +# Boltz backend supports sending messages to Discord after successful and failed +# Swaps and if the wallet or channel balance is below a configurable threshold [notification] token = "" channel = "" @@ -93,15 +98,6 @@ otpsecretpath = "/home/boltz/.boltz/otpSecret.dat" # - Poloniex # - "fee": percentage of the swapped amount that should be charged as fee # - "swapInFee" (optional): same as "fee" but for swaps from onchain to lightning; defaults to "fee" if not set - -[[pairs]] -base = "LTC" -quote = "BTC" -timeoutDelta = 400 - -maxSwapAmount = 10_000_000 -minSwapAmount = 10_000 - [[pairs]] base = "BTC" quote = "BTC" @@ -116,11 +112,9 @@ minSwapAmount = 10_000 # reverse = 1440 # swapMinimal = 1440 # swapMaximal = 2880 - - [[pairs]] -base = "LTC" -quote = "LTC" +base = "L-BTC" +quote = "BTC" rate = 1 fee = 0.5 swapInFee = 0.2 @@ -168,27 +162,4 @@ maxZeroConfAmount = 10_000_000 certpath = "/home/boltz/.lnd/bitcoin/tls.cert" macaroonpath = "/home/boltz/.lnd/bitcoin/admin.macaroon" maxPaymentFeeRatio = 0.03 - -[[currencies]] -symbol = "LTC" -network = "litecoinTestnet" -minWalletBalance = 20_000_000 -minChannelBalance = 0 -maxZeroConfAmount = 1_000_000_000 - - [currencies.chain] - host = "127.0.0.1" - port = 19_332 - - cookie = "" - - user = "litecoin" - password = "litecoin" - - [currencies.lnd] - host = "127.0.0.1" - port = 11_009 - certpath = "/home/boltz/.lnd/litecoin/tls.cert" - macaroonpath = "/home/boltz/.lnd/litecoin/admin.macaroon" - maxPaymentFeeRatio = 0.03 ``` diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 6474590c..00000000 --- a/docs/index.md +++ /dev/null @@ -1,25 +0,0 @@ -# Boltz v3.2.0 Documentation - -This is the documentation of [Boltz](https://boltz.exchange) version v3.2.0. - -## What is Boltz - -Boltz is a privacy first, account-free crypto exchange built on top of second layer scaling technologies like the [lightning network](http://lightning.network/). Boltz doesn't track any data that could potentially be traced back to the identity of our users. - -## Instances - -We are running and maintaining two Boltz instances that can be used - one on [testnet](https://testnet.boltz.exchange) and one on [mainnet](https://boltz.exchange). - -The Rest API can be accessed at: - -* [Testnet](https://testnet.boltz.exchange/api) -* [Mainnet](https://api.boltz.exchange) - -> Note: If you access the API from your browser, you will get 404. -> Run `curl https://api.boltz.exchange/version`, (or `curl https://testnet.boltz.exchange/api/version` for testnet) to check that it is available. - -## Useful Links - -* [Source Code](https://github.com/boltzexchange) -* [Frequently Asked Questions](https://boltz.exchange/faq) -* [Discord](https://discordapp.com/invite/QBvZGcW) [![Discord](https://img.shields.io/discord/547454030801272832.svg)](https://discordapp.com/invite/QBvZGcW) diff --git a/docs/lifecycle.md b/docs/lifecycle.md index e16bc5e0..585f084a 100644 --- a/docs/lifecycle.md +++ b/docs/lifecycle.md @@ -1,30 +1,38 @@ -# Swap Lifecycle +--- +description: >- + Boltz offers several different swap types. This document describes the types + and different states a particular swap type traverses. +--- -## Introduction +# ๐Ÿ” Swap Types & States -There are two types of [Atomic Swaps](https://en.bitcoin.it/wiki/Atomic_swap): +## Swap Types -- [Normal Submarine Swaps](#normal-submarine-swaps) -- [Reverse Submarine Swaps](#reverse-submarine-swaps) +Boltz currently offers two types of [Atomic Swaps](https://en.bitcoin.it/wiki/Atomic\_swap): -## Normal Submarine Swaps +* [Normal Submarine Swaps](lifecycle.md#normal-submarine-swaps) (Chain -> Lightning) +* [Reverse Submarine Swaps](lifecycle.md#reverse-submarine-swaps) (Lightning -> Chain) -Normal swaps are from onchain coins to lightning ones. Which means the user creates an invoice, sends coins to an provided onchain address and Boltz takes care of everything else. When a normal swap is created it doesn't have a status until: +## Swap States -1. `swap.created`: initial status of the Submarine Swap; the initial status could also be `invoice.set` in case the invoice was specified in the request creating the swap -2. `transaction.mempool`: a transaction that sends coins to the onchain address of the swap is found in the mempool -3. `transaction.confirmed`: that transaction was included in a block -4. `invoice.set`: when the invoice of the Submarine Swap was set -5. once the said transaction is included in a block (or found in the mempool in case of [0-confirmation](0-confirmation.md)) Boltz will try to pay the invoice provided by the user in order to claim the onchain coins - - `invoice.paid`: if paying the invoice was successful - - `invoice.failedToPay`: if paying the invoice failed. In which case the locked up onchain coins should be refunded -6. `transaction.claimed`: indicates that the invoice was successfully paid for and that the onchain coins were claimed by the Boltz instance +### Normal Submarine Swaps -If the user doesn't send onchain coins until the time lock is expired, Boltz will set the status of the swap to `swap.expired` which means that it was abandoned and sending onchain coins will have no effect. +"Normal Submarine Swaps" move bitcoin from the chain to Lightning. "Chain" can be the Bitcoin mainchain or, for instance, the Liquid sidechain. Typically the user creates a Lightning invoice, sends bitcoin to a provided chain address and Boltz takes care of everything else. -For more information about the refunding onchain coins, checkout the [scripting docs](scripting.md). +When a Normal Submarine Swap is created, it passes through the following states: -When a Channel Creation is involved in the Swap protocol, the backend will send the event `channel.created` after `transaction.confirmed`. This event means that a channel has been opened to the requested node. Alongside the status update, the JSON object `channel` is sent, which contains information about the funding transaction of the opened channel: +1. `swap.created`: initial state of the swap; _optionally_ the initial state can also be `invoice.set` in case the invoice was already specified in the `/createswap` request. [Boltz Web App](https://github.com/BoltzExchange/boltz-web-app) is an example for a client that sets the invoice with `/createswap` already. +2. `transaction.mempool`: a transaction that sends bitcoin to the chain address is found in the mempool, meaning user sent funds to the lockup chain address. +3. `transaction.confirmed`: the lockup transaction was included in a block. For mainchain swaps, Boltz always waits for one confirmation before continuing with the swap. The [`getpairs`](api.md#supported-pairs) call provides amount limits for which Boltz accepts [0-conf](0-confirmation.md#limits) per pair. +4. `invoice.set`: if the invoice was _not_ set as part of the `/createswap` request, this state confirms that an invoice with the correct amount and hash was set. +5. Once the user's lockup transaction is included in a block (or found in the mempool in case [0-conf](0-confirmation.md) applies), Boltz will try to pay the invoice provided by the user. When successful, Boltz obtains the preimage needed to claim the chain bitcoin. State of the Lightning payment is either: + * `invoice.paid`: if paying the invoice was successful or + * `invoice.failedToPay`: if paying the invoice failed. In this case the user needs to broadcast a refund transaction to reclaim the locked up chain bitcoin +6. `transaction.claimed`: indicates that after the invoice was successfully paid, the chain Bitcoin were successfully claimed _by Boltz_. This is the final status of a successful Normal Submarine swap. + +If the user doesn't send chain bitcoin and the swap expires (approximately 24h), Boltz will set the state of the swap to `swap.expired` , which means that it was cancelled and chain bitcoin shouldn't be sent anymore. In case of `invoice.failedToPay` or `swap.expired` but bitcoin were sent, the user needs to submit a refund transaction to reclaim their locked chain bitcoin. For more information about how clients can construct & submit refund transactions for users, check out the [scripting](scripting.md) section. + +When a "Channel Creation" is involved in the swap protocol, Boltz will send the event `channel.created` after `transaction.confirmed`. This event means that a channel has been opened to the requested node. Alongside the state update, the `JSON` object `channel` is sent, which contains information about the funding transaction of the opened channel: ```json { @@ -36,20 +44,20 @@ When a Channel Creation is involved in the Swap protocol, the backend will send } ``` -## Reverse Submarine Swaps +### Reverse Submarine Swaps -Reverse swaps are from lightning to onchain coins. In this scenario the user generates a preimage, creates SHA256 hash of it and sends that hash to Boltz. With that hash Boltz creates a hold invoice, that can only be settled when the preimage is revealed to the boltz backend. The user pays that invoice, but the lightning coins are not transferred to Boltz yet because it doesn't know the preimage. Therefore, the backend locks up onchain coins using the same hash so that these can be claimed with the preimage. When the claim transaction is broadcasted by the user, Boltz detects the preimage and in turn claims the lightning coins. +"Reverse Submarine Swaps" move bitcoin from Lightning to the chain. Again, "chain" can refer to the Bitcoin mainchain or, for instance, the Liquid sidechain. "Reverse Submarine Swaps" start with the client generating a preimage, then a SHA256 hash of it and sending that hash to Boltz. With this hash Boltz creates a hold invoice, that can only be settled when the preimage is revealed. The user pays the invoice, but the Lightning payment doesn't execute yet because Boltz doesn't know the preimage to claim it. Next, Boltz locks up chain bitcoin using the same hash so that these can be claimed with the previously generated preimage by the client. When the claim transaction for the chain bitcoin is broadcasted by the user, Boltz detects the preimage and in turn claims the lightning bitcoin. The [scripting](scripting.md) section contains details about how clients can construct claim transactions for their users. -The [scripting docs](scripting.md) contain details about constructing claim transactions. +The following states are traversed in the course of a Reverse Submarine Swap: -1. `swap.created`: initial status of the Reverse Submarine Swap -2. `minerfee.paid`: only if the instance requires prepaying miner fees (our official instance do not) or the Reverse Swap enabled the Ethereum prepay miner fee; event is sent when the miner fee invoice is paid -3. `transaction.mempool`: the lockup transaction is found in the mempool which will happen after the user pay the hold invoice -4. `transaction.confirmed`: the lockup transaction is included in a block. This status can and will be skipped if the user wants to accept a 0-conf transaction -5. `invoice.settled`: the transaction claiming the onchain coins was broadcasted and Boltz received the offchain coins +1. `swap.created`: initial state of the Reverse Submarine Swap +2. `minerfee.paid`: optional and currently not enabled on Boltz. If Boltz requires prepaying miner fees via a separate Lightning invoice, this event is sent when the miner fee invoice is paid +3. `transaction.mempool`: Boltz's lockup transaction is found in the mempool which will only happen after the user paid the Lightning hold invoice +4. `transaction.confirmed`: the lockup transaction was included in a block. This state is skipped if the client optionally accepts the transaction without confirmation. Boltz broadcasts chain transactions non-RBF only. +5. `invoice.settled`: the transaction claiming chain Bitcoin was broadcasted and Boltz received the Lightning bitcoin. This is the final status of a successful Reverse Submarine Swap. -The status update `invoice.expired` is sent when the invoice(s) of Boltz expire and pending HTLCs are cancelled. +The status `invoice.expired` is set when the invoice of Boltz expired and pending HTLCs are cancelled. If the swap expires without the lightning invoice being paid, the status of the swap will be `swap.expired`. -If Boltz is unable to send the agreed amount of onchain coins after the invoice is paid, the status of the status will become `transaction.failed` and the pending lightning HTLC will be cancelled. +If Boltz for some reason is unable to send the agreed amount of chain bitcoin after the user paid the Lightning invoice, the status of the swap will be `transaction.failed` and the pending lightning HTLC will be cancelled. The Lightning bitcoin automatically bounce back to the user, no further action or refund is required and the user didn't pay any fees. -In case of the timelock expiring, Boltz will automatically refund its locked up coins. The status of the reverse swap will change to `transaction.refunded` and paying the invoice becomes futile because the locked up coins were already spent by the refunding transaction and only cause a pending HTLC in one of the channels of the user. If the reverse swap expires before the invoice is paid, the status of the swap will change to `swap.expired`. +In case of the chain timelock expiring, Boltz will automatically refund its own locked chain Bitcoin. The status of the swap will be `transaction.refunded` and paying the invoice becomes futile because the locked up Bitcoin were already claimed back by Boltz and only cause a pending Lightning HTLC for the user, the payment won't execute. diff --git a/docs/regtest.md b/docs/regtest.md index cbf8e127..3ce81ea3 100644 --- a/docs/regtest.md +++ b/docs/regtest.md @@ -1,25 +1,19 @@ -# Setting up the regtest Docker environment +--- +description: This Document describes a Docker regtest environment for development purposes. +--- -Prerequisites: +# ๐Ÿณ Docker Regtest Environment -* Node.js version `v18.16.1` or higher (preferably the latest LTS) -* Docker +Prerequisites: -The regtest environment of the Boltz backend is based on this Docker image [boltz/regtest](https://hub.docker.com/r/boltz/regtest) (Bitcoin Core, Litecoin Core and 2 LNDs on each chain) +* The latest [Node.js LTS and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed. We recommend using [nvm](https://github.com/nvm-sh/nvm#install--update-script) to manage npm installs: `nvm install --lts` +* [Docker](https://docs.docker.com/engine/install/) -To start those images run `npm run docker:start` and to stop them again use `npm run docker:stop` to stop and remove the containers. +The regtest environment of Boltz Backend is based on [boltz/regtest](https://hub.docker.com/r/boltz/regtest). To start the images run `npm run docker:start` and to stop them again use `npm run docker:stop` to stop and remove the containers. -To use the nodes in the container with Boltz backend use a configuration similar to this one: +To use the nodes in the container with Boltz Backend, use a configuration similar to this one: ```toml -[[pairs]] -base = "LTC" -quote = "BTC" -fee = 2 -timeoutDelta = 400 -maxSwapAmount = 4_294_967 -minSwapAmount = 10_000 - [[pairs]] base = "BTC" quote = "BTC" @@ -30,30 +24,14 @@ maxSwapAmount = 4_294_967 minSwapAmount = 10_000 [[pairs]] -base = "LTC" -quote = "LTC" +base = "L-BTC" +quote = "BTC" rate = 1 fee = 0.5 timeoutDelta = 1_440 maxSwapAmount = 2_000_000_000 minSwapAmount = 100_000 -[[pairs]] -base = "ETH" -quote = "BTC" -fee = 5 -timeoutDelta = 180 -maxSwapAmount = 4_294_967 -minSwapAmount = 50_000 - -[[pairs]] -base = "BTC" -quote = "USDT" -fee = 5 -timeoutDelta = 180 -maxSwapAmount = 4_294_967 -minSwapAmount = 50_000 - [[currencies]] symbol = "BTC" network = "bitcoinRegtest" @@ -75,27 +53,6 @@ maxZeroConfAmount = 10_000_000 macaroonpath = "docker/regtest/data/lnd/macaroons/admin.macaroon" maxPaymentFeeRatio = 0.03 -[[currencies]] -symbol = "LTC" -network = "litecoinRegtest" -minWalletBalance = 110_000_000 -minChannelBalance = 110_000_000 -maxZeroConfAmount = 0 - - [currencies.chain] - host = "127.0.0.1" - port = 19_443 - cookie = "docker/regtest/data/core/cookies/.litecoin-cookie" - rpcuser = "kek" - rpcpass = "kek" - - [currencies.lnd] - host = "127.0.0.1" - port = 11_009 - certpath = "docker/regtest/data/lnd/certificates/tls.cert" - macaroonpath = "docker/regtest/data/lnd/macaroons/admin.macaroon" - maxPaymentFeeRatio = 0.03 - [liquid] symbol = "L-BTC" network = "liquidRegtest" @@ -105,23 +62,9 @@ minWalletBalance = 10_000_000 host = "127.0.0.1" port = 18884 cookie = "docker/regtest/data/core/cookies/.elements-cookie" - -[ethereum] -providerEndpoint = "http://127.0.0.1:8546" - -etherSwapAddress = "0xc6105E7F62690cee5bf47f8d8A353403D93eCC6B" -erc20SwapAddress = "0x0Cd61AD302e9B2D76015050D44218eCF53cFadC9" - - [[ethereum.tokens]] - symbol = "ETH" - - [[ethereum.tokens]] - symbol = "USDT" - decimals = 18 - contractAddress = "0x504eF817bFdE039b33189C7eb8aa8861c25392C1" ``` -It is really handy to have the executables of Boltz and some aliases to control the nodes in your path. Therefore, it is recommended to add the following to your `.bashrc`: +We recommend adding aliases to control executables of Boltz and nodes to your `.bashrc`: ```bash # Boltz Docker regtest @@ -131,17 +74,12 @@ boltzDataDir="$boltzDir/docker/regtest/data/" cookieDir="$boltzDataDir/core/cookies" alias bitcoin-cli-sim='bitcoin-cli --regtest --rpccookiefile=$cookieDir/.bitcoin-cookie' -alias litecoin-cli-sim='litecoin-cli --regtest --rpccookiefile=$cookieDir/.litecoin-cookie' - lndCert="$boltzDataDir/lnd/certificates/tls.cert" lndMacaroon="$boltzDataDir/lnd/macaroons/admin.macaroon" alias lnclibtc='lncli --rpcserver=127.0.0.1:10009 --tlscertpath=$lndCert --macaroonpath=$lndMacaroon' alias lnclibtc2='lncli --rpcserver=127.0.0.1:10011 --tlscertpath=$lndCert --macaroonpath=$lndMacaroon' -alias lncliltc='lncli --rpcserver=127.0.0.1:11009 --tlscertpath=$lndCert --macaroonpath=$lndMacaroon' -alias lncliltc2='lncli --rpcserver=127.0.0.1:11010 --tlscertpath=$lndCert --macaroonpath=$lndMacaroon' - # Add the Boltz executables to the path export PATH="$boltzDir/bin:$PATH" ``` diff --git a/docs/scripting.md b/docs/scripting.md index 7dfd23d7..3c58725c 100644 --- a/docs/scripting.md +++ b/docs/scripting.md @@ -1,20 +1,26 @@ -# Scripting +--- +description: >- + This section gives you an overview of the low-level scripting that might be + required for your Boltz API client. +--- -## UTXO based chains +# ๐Ÿงพ Scripting -Boltz theoretically supports three types of outputs and addresses: +## UTXO Chains -- P2SH -- P2SH nested P2WSH -- P2WSH +Boltz supports three types of outputs and addresses: -Our instances are using *P2SH nested P2WSH* addresses for Submarine Swaps and *P2WSH* addresses for Reverse ones. The address type for Submarine Swaps is [configurable](deployment.md) and can be either *P2WSH* or *P2SH nested P2WSH*. +* P2SH +* P2SH nested P2WSH +* P2WSH + +Boltz is currently using _P2SH nested P2WSH_ addresses for Normal Submarine Swaps and _P2WSH_ addresses for Reverse Submarine Swaps. The address type for Submarine Swaps is [configurable](deployment.md) and can be either _P2WSH_ or _P2SH nested P2WSH_. ### Address Generation -The Boltz API returns a redeem script, and an address for locking up coins. After verifying that the redeem script is valid (checking preimage hash, public key, timeout block height of the HTLC and OP codes), the correctness of the address should be double-checked. +Boltz API returns a redeem script and an address for locking up coins. After verifying that the redeem script is valid (checking preimage hash, public key, timeout block height of the HTLC and OP codes), the correctness of the address should be double-checked. -A list of all OP codes and their meanings can be found on the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Script). +A list of all OP codes and their meaning can be found on the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Script). #### P2SH @@ -47,7 +53,7 @@ OP_EQUAL #### Examples -Examples for generating all of these addresses with Node.js can be found in the [`boltz-core` repository](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Scripts.ts). +Examples for generating all of these addresses with `Node.js` can be found in the [`boltz-core`](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Scripts.ts) reference library. ### Claim transactions @@ -69,34 +75,22 @@ Spending a P2WSH output is similar to the P2SH ones. But here those values are a #### P2SH nested P2WSH -When spending a P2SH nested P2WSH output the signature, preimage and original reedem script are added to the witness of the input as if the output was a P2WSH one, but you also have to add the OP code `OP_0` and the SHA256 hash of the redeem script to the signature script of the input. +When spending a P2SH nested P2WSH output the signature, preimage and original reedem script are added to the witness of the input as if the output was a P2WSH one, but you also have to add the OP code `OP_0` and the SHA256 hash of the redeem script to the signature script of the input. #### Examples -Examples for all three output types can be found in the [`boltz-core` repository](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Claim.ts#L23). +Examples for all three output types can be found in the [`boltz-core` ](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Claim.ts#L23)reference library. ### Refund transactions -Refunding an output works just like claiming. Since the refunder doesn't know the preimage (or knows it but can't use it since that would require the claim keys) any value apart from the actual preimage can be used but there has to be a value to prevent the signature from being hashed and compared to the preimage hash. To save transaction fees, a 0 value should be used. +Refunding an output works just like claiming. Since the refund process doesn't know the preimage (or knows it but can't use it since that would require the claim keys) any value apart from the actual preimage can be used but there has to be a value to prevent the signature from being hashed and compared to the preimage hash. To save transaction fees, a 0 value should be used. There is one more difference when compared to claim transactions: the `nLockTime` of the transaction has to be set to a value equal to or greater than the timeout block height of the HTLC. Else the bitcoin network will not accept your transaction. #### Examples -An example for this can be found in the [`boltz-core` repository](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Refund.ts#L20). The linked function uses the claim function from above but requires the timeout block height as argument and sets an empty preimage. +An example for this can be found in the [`boltz-core`](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Refund.ts#L20) reference library. The linked function uses the claim function from above but requires the timeout block height as argument and sets an empty preimage. ## EVM chains -The HTLCs that Boltz uses on EVM chains are not single use scripts but contracts. One contract is called EtherSwap and the other one is ERC20Swap. The source for the those contracts and some additional ones used for integration testing the Swap contracts can be found [in the `boltz-core` repository](https://github.com/BoltzExchange/boltz-core/tree/master/contracts). - -### EtherSwap - -Is used to, as the name indicates, swap Ether. [The way it transfers Ether out of the contract](https://github.com/BoltzExchange/boltz-core/blob/v0.4.1/contracts/TransferHelper.sol#L14) forwards all leftover gas which means that other contracts can easily build on top of it. - -On mainnet the latest version of the contract is deployed at [0x76C725fEA03B179d326a3689C36218c0a3b42720](https://etherscan.io/address/0x76C725fEA03B179d326a3689C36218c0a3b42720). - -### ERC20Swap - -Works exactly like EtherSwap but is used for ERC20 tokens. - -On mainnet the latest version of the contract is deployed at [0x964B943cF21A9f8987d80F9143955d7aed14F78A](https://etherscan.io/address/0x964B943cF21A9f8987d80F9143955d7aed14F78A). +The HTLCs that Boltz uses on EVM chains are not single use scripts, but contracts. The source for the those contracts and integration tests can be found in the [`boltz-core`](https://github.com/BoltzExchange/boltz-core/tree/master/contracts) [r](https://github.com/BoltzExchange/boltz-core/blob/master/lib/swap/Scripts.ts)eference library. diff --git a/docs/swap-files.md b/docs/swap-files.md index 55ec2728..add6892b 100644 --- a/docs/swap-files.md +++ b/docs/swap-files.md @@ -1,21 +1,28 @@ -# Swap files +--- +description: >- + With refund files, users reclaim funds of a failed Normal Submarine Swap. They + are the last layer of defense against loss of funds, in case refund info + stored by the client is lost. +--- -All applications that save files for Swaps to the disk should format them in a standardized way. This is especially important for Normal Submarine Swaps so that they can be refunded not only in the application but also in our Boltz frontend. +# ๐Ÿ“ฉ Refund Files + +The concept of refunds currently only exists for failed Normal Submarine Swaps. In case of a failed Reverse Submarine Swaps, Lightning funds automatically bounce back to the user, no active refunding is needed. All clients that offer the option for users to save refund files should format them in a standardized way. This is necessary for refunds to not only work in a client, but also but also with the [Boltz Web App](https://boltz.exchange/refund). ## Refund Files -The refund files our frontend generates are PNG QR codes because iOS browsers don't allow any other files than images to be downloaded to the device. This might not be applicable to you and therefore our frontend also parses files with any other extension and treats them as raw JSON. - -The data that should be in the file or encoded in the QR code is a JSON object with the following values: - - - `id`: the ID of the swap - - `currency`: symbol of the chain on which coins were locked up - - `redeemScript`: the redeem script of the lockup address - - `privateKey`: the private key of the refund key pair - - `timeoutBlockHeight`: block height at which the Swaps times out - -The values of `id`, `redeemScript` and `timeoutBlockHeight` are returned by the Boltz API when the Swap gets created. `currency` and `privateKey` are obviously known by the application anyways. - +The refund files Boltz Web App generates are `JSON` on Desktop and `PNG` QR codes on mobile because iOS browsers don't allow any other files than images to be downloaded. Boltz parses files with other extension than `.json` and `.png` and treats them as raw `JSON`. + +The data that should be in the file or encoded in the QR code is a `JSON` object with the following values: + +* `id`: the ID of the swap +* `currency`: symbol of the chain on which bitcoin were locked up +* `redeemScript`: the redeem script of the lockup address +* `privateKey`: the private key of the refund key pair +* `timeoutBlockHeight`: block height at which the swap times out + +The values of `id`, `redeemScript` and `timeoutBlockHeight` are returned by the Boltz API when the Swap is created. `currency` and `privateKey` are known by the client already. + Example: ```json