From 7a2e5995fc02649ad1198bfdcfd6a0c7b149fed4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 26 May 2017 11:15:57 +0300 Subject: [PATCH] Test --- iguana/exchanges/DEXstats.h | 17 +- iguana/exchanges/LP_bitcoin.c | 692 +++++ iguana/exchanges/LP_commands.c | 105 + .../{LP_unspents.c => LP_nativeDEX.c} | 90 +- iguana/exchanges/LP_prices.c | 41 + iguana/exchanges/LP_remember.c | 1168 ++++++++ iguana/exchanges/LP_swap.c | 2379 +++++++++++++++++ iguana/exchanges/mm.c | 16 +- iguana/kmd_lookup.h | 11 +- 9 files changed, 4454 insertions(+), 65 deletions(-) create mode 100644 iguana/exchanges/LP_bitcoin.c create mode 100644 iguana/exchanges/LP_commands.c rename iguana/exchanges/{LP_unspents.c => LP_nativeDEX.c} (88%) create mode 100644 iguana/exchanges/LP_prices.c create mode 100644 iguana/exchanges/LP_remember.c create mode 100644 iguana/exchanges/LP_swap.c diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 5738ab91e..6982cb64d 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -1,10 +1,21 @@ +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ // // DEXstats.h // marketmaker // -// Created by Mac on 5/7/17. -// Copyright © 2017 SuperNET. All rights reserved. -// #ifndef DEXstats_h #define DEXstats_h diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c new file mode 100644 index 000000000..421d889ca --- /dev/null +++ b/iguana/exchanges/LP_bitcoin.c @@ -0,0 +1,692 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_bitcoin.c +// marketmaker +// + +#define IGUANA_MAXSCRIPTSIZE 10001 + +struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; //PACKEDSTRUCT; + +struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; }; + +struct vin_info +{ + struct iguana_msgvin vin; uint64_t amount; cJSON *extras; bits256 sigtxid; + int32_t M,N,validmask,spendlen,type,p2shlen,numpubkeys,numsigs,height,hashtype,userdatalen,suppress_pubkeys,ignore_cltverr; + uint32_t sequence,unspentind; struct vin_signer signers[16]; char coinaddr[65]; + uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE],userdata[IGUANA_MAXSCRIPTSIZE]; +}; + +#define SIGHASH_ALL 1 +#define SIGHASH_NONE 2 +#define SIGHASH_SINGLE 3 +#define SIGHASH_ANYONECANPAY 0x80 + +#define SCRIPT_OP_NOP 0x00 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_4 0x54 +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_RETURN 0x6a +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_DROP 0x75 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_SHA256 0xa8 +#define SCRIPT_OP_HASH160 0xa9 + +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 + +void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen) +{ + bits256 hash; + vcalc_sha256(0,hash.bytes,data,datalen); + calc_rmd160(0,rmd160,hash.bytes,sizeof(hash)); +} + +void revcalc_rmd160_sha256(uint8_t rmd160[20],bits256 revhash) +{ + bits256 hash; int32_t i; + for (i=0; i<32; i++) + hash.bytes[i] = revhash.bytes[31-i]; + calc_rmd160_sha256(rmd160,hash.bytes,sizeof(hash)); +} + +bits256 revcalc_sha256(bits256 revhash) +{ + bits256 hash,dest; int32_t i; + for (i=0; i<32; i++) + hash.bytes[i] = revhash.bytes[31-i]; + vcalc_sha256(0,dest.bytes,hash.bytes,sizeof(hash)); + return(dest); +} + +int32_t bitcoin_pubkeylen(const uint8_t *pubkey) +{ + if ( pubkey[0] == 2 || pubkey[0] == 3 ) + return(33); + else if ( pubkey[0] == 4 ) + return(65); + else + { + //printf("illegal pubkey.[%02x] %llx\n",pubkey[0],*(long long *)pubkey); + return(-1); + } +} + +int32_t bitcoin_pubkeyspend(uint8_t *script,int32_t n,uint8_t pubkey[66]) +{ + int32_t plen = bitcoin_pubkeylen(pubkey); + script[n++] = plen; + memcpy(&script[n],pubkey,plen); + n += plen; + script[n++] = SCRIPT_OP_CHECKSIG; + return(n); +} + +int32_t bitcoin_p2shspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) +{ + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; + script[n++] = SCRIPT_OP_EQUAL; + return(n); +} + +int32_t bitcoin_secret160verify(uint8_t *script,int32_t n,uint8_t secret160[20]) +{ + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; + memcpy(&script[n],secret160,0x14); + n += 0x14; + script[n++] = SCRIPT_OP_EQUALVERIFY; + return(n); +} + +int32_t bitcoin_secret256spend(uint8_t *script,int32_t n,bits256 secret) +{ + script[n++] = SCRIPT_OP_SHA256; + script[n++] = 0x20; + memcpy(&script[n],secret.bytes,0x20); + n += 0x20; + script[n++] = SCRIPT_OP_EQUAL; + return(n); +} + +// OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +int32_t bitcoin_standardspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) +{ + script[n++] = SCRIPT_OP_DUP; + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; + script[n++] = SCRIPT_OP_EQUALVERIFY; + script[n++] = SCRIPT_OP_CHECKSIG; + return(n); +} + +int32_t bitcoin_checklocktimeverify(uint8_t *script,int32_t n,uint32_t locktime) +{ + script[n++] = 4; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff; + script[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; + script[n++] = SCRIPT_OP_DROP; + return(n); +} + +int32_t bitcoin_timelockspend(uint8_t *script,int32_t n,uint8_t rmd160[20],uint32_t timestamp) +{ + n = bitcoin_checklocktimeverify(script,n,timestamp); + n = bitcoin_standardspend(script,n,rmd160); + return(n); +} + +int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp) +{ + int32_t i,plen; + script[n++] = 0x50 + vp->M; + for (i=0; iN; i++) + { + if ( (plen= bitcoin_pubkeylen(vp->signers[i].pubkey)) < 0 ) + return(-1); + script[n++] = plen; + memcpy(&script[n],vp->signers[i].pubkey,plen); + n += plen; + } + script[n++] = 0x50 + vp->N; + script[n++] = SCRIPT_OP_CHECKMULTISIG; + calc_rmd160_sha256(p2sh_rmd160,script,n); + return(n); +} + +int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,const int32_t p2shlen) +{ + if ( p2shlen >= 0xfd ) + { + script[n++] = 0x4d; + script[n++] = (p2shlen & 0xff); + script[n++] = ((p2shlen >> 8) & 0xff); + } + else if ( p2shlen > 76 ) + { + script[n++] = 0x4c; + script[n++] = p2shlen; + } else script[n++] = p2shlen; + memcpy(&script[n],p2shscript,p2shlen), n += p2shlen; + return(n); +} + +bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) +{ + bits256 reveal; +#ifdef DISABLE_CHECKSIG + vcalc_sha256(0,reveal.bytes,privkey.bytes,sizeof(privkey)); + //reveal = revcalc_sha256(privkey); + char str[65],str2[65]; printf("priv.(%s) -> reveal.(%s)\n",bits256_str(str,privkey),bits256_str(str2,reveal)); +#else + reveal = pubkey; +#endif + return(reveal); +} + +int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) +{ + int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],secret160[20],secret256[32]; + if ( depositflag != 0 ) + { + pubkeyA[0] = 0x02, cltvpub = pubA0; + pubkeyB[0] = 0x03, destpub = pubB0; + privkey = privBn; + memcpy(secret160,secretBn,20); + memcpy(secret256,secretBn256,32); + } + else + { + pubkeyA[0] = 0x03, cltvpub = pubB1; + pubkeyB[0] = 0x02, destpub = pubA0; + privkey = privAm; + memcpy(secret160,secretAm,20); + memcpy(secret256,secretAm256,32); + } + //for (i=0; i<32; i++) + // printf("%02x",secret256[i]); + //printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); + if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) + return(-1); + for (i=0; i<20; i++) + if ( secret160[i] != 0 ) + break; + if ( i == 20 ) + return(-1); + memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub)); + memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub)); + redeemscript[n++] = SCRIPT_OP_IF; + n = bitcoin_checklocktimeverify(redeemscript,n,locktime); +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,cltvpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyA); +#endif + redeemscript[n++] = SCRIPT_OP_ELSE; + if ( secretstartp != 0 ) + *secretstartp = n + 2; + if ( 1 ) + { + if ( 1 && bits256_nonz(privkey) != 0 ) + { + uint8_t bufA[20],bufB[20]; + revcalc_rmd160_sha256(bufA,privkey); + calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); + /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + printf("MATCHES BUFA\n"); + else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) + printf("MATCHES BUFB\n"); + else printf("secret160 matches neither\n"); + for (i=0; i<20; i++) + printf("%02x",bufA[i]); + printf(" <- revcalc\n"); + for (i=0; i<20; i++) + printf("%02x",bufB[i]); + printf(" <- calc\n");*/ + memcpy(secret160,bufB,20); + } + n = bitcoin_secret160verify(redeemscript,n,secret160); + } + else + { + redeemscript[n++] = 0xa8;//IGUANA_OP_SHA256; + redeemscript[n++] = 0x20; + memcpy(&redeemscript[n],secret256,0x20), n += 0x20; + redeemscript[n++] = 0x88; //SCRIPT_OP_EQUALVERIFY; + } +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,destpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyB); +#endif + redeemscript[n++] = SCRIPT_OP_ENDIF; + return(n); +} + +int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct basilisk_swapinfo *swap,int32_t depositflag) +{ + if ( depositflag != 0 ) + *locktimep = swap->started + swap->putduration + swap->callduration; + else *locktimep = swap->started + swap->putduration; + *redeemlenp = n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); + if ( n > 0 ) + { + calc_rmd160_sha256(rmd160,redeemscript,n); + n = bitcoin_p2shspend(script,0,rmd160); + //for (i=0; i= 0 ) + { + if ( (scriptlen= iguana_scriptsigextract(myinfo,coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) + { + for (i=0; i<32; i++) + privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; + revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); + if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) + { + *destp = privkey; + printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); + return(0); + } + } + } + return(-1); +} + +int32_t basilisk_confirmsobj(cJSON *item) +{ + int32_t height,numconfirms; + height = jint(item,"height"); + numconfirms = jint(item,"numconfirms"); + if ( height > 0 && numconfirms >= 0 ) + return(numconfirms); + printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); + return(-1); +} + +int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + cJSON *argjson,*valuearray=0; char *valstr; int32_t i,n,retval = -1; +#ifdef BASILISK_DISABLEWAITTX + return(100); +#endif + argjson = cJSON_CreateObject(); + jaddbits256(argjson,"txid",rawtx->I.actualtxid); + jaddnum(argjson,"vout",0); + jaddstr(argjson,"coin",rawtx->coin->symbol); + if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) + { + char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) + + if ( (valuearray= cJSON_Parse(valstr)) != 0 ) + { + if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) + { + n = cJSON_GetArraySize(valuearray); + for (i=0; i= 0 ) + break; + } + } else retval = basilisk_confirmsobj(valuearray); + free_json(valuearray); + } else printf("parse error\n"); + free(valstr); + } + free_json(argjson); + printf("numconfirms.%d returned\n",retval); + return(retval); +} + +bits256 basilisk_swap_broadcast(char *name,struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,uint8_t *data,int32_t datalen) +{ + bits256 txid; char *signedtx,*retstr; int32_t i; + memset(txid.bytes,0,sizeof(txid)); + if ( data != 0 && datalen != 0 ) + { + char str[65]; +#ifdef BASILISK_DISABLESENDTX + txid = bits256_doublesha256(0,data,datalen); + printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); + return(txid); +#endif + signedtx = malloc(datalen*2 + 1); + init_hexbytes_noT(signedtx,data,datalen); + for (i=0; i<3; i++) + { + if ( (retstr= basilisk_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + free(retstr); + printf("sendrawtransaction %s.(%s)\n",name,bits256_str(str,txid)); + break; + } + else + { + printf("sendrawtransaction %s error.(%s)\n",name,retstr); + free(retstr); + } + } else printf("sendrawtransaction %s got null return\n",name); + } + free(signedtx); + } + return(txid); +} + +int32_t _basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; + V = calloc(256,sizeof(*V)); + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,rawtx->coin->chain->wiftype); + jaddistr(privkeys,wifstr); + if ( privkey2 != 0 ) + { + V[0].signers[1].privkey = *privkey2; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2); + bitcoin_priv2wif(wifstr,*privkey2,rawtx->coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); + } else V[0].N = V[0].M = 1; + V[0].suppress_pubkeys = dest->I.suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( dest->I.redeemlen != 0 ) + memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; + txobj = bitcoin_txcreate(rawtx->coin->symbol,rawtx->coin->chain->isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->chain->locktime_txversion); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); +#ifdef DISABLE_CHECKSIG + needsig = 0; +#endif + } + //printf("rawtx B\n"); + if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) + jaddbits256(item,"txid",rawtx->I.actualtxid); + else jaddbits256(item,"txid",rawtx->I.signedtxid); + jaddnum(item,"vout",0); + sobj = cJSON_CreateObject(); + init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",dest->I.suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) + { + init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); + memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); + txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); + if ( (rawtxbytes= bitcoin_json2hex(myinfo,rawtx->coin,&dest->I.txid,txobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( needsig == 0 ) + signedtx = rawtxbytes; + if ( signedtx != 0 || (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + dest->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( dest->I.datalen <= sizeof(dest->txbytes) ) + decode_hex(dest->txbytes,dest->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( dest->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(retval); +} + +int32_t basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; + timestamp = swap->I.started; + if ( dest == &swap->aliceclaim ) + locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; + else if ( dest == &swap->bobreclaim ) + locktime = swap->bobpayment.I.locktime + 1, sequenceid = 0; + return(_basilisk_rawtx_sign(myinfo,height,timestamp,locktime,sequenceid,dest,rawtx,privkey,privkey2,userdata,userdatalen,ignore_cltverr)); +} + +cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *vins) +{ + cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; + privkeyarray = cJSON_CreateArray(); + //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); + if ( (n= cJSON_GetArraySize(vins)) > 0 ) + { + for (i=0; i= 0 ) + { + iguana_txidcategory(myinfo,coin,account,coinaddr,txid,vout); + if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) + { + len = (int32_t)strlen(hexstr) >> 1; + if ( len < (sizeof(script) << 1) ) + { + decode_hex(script,len,hexstr); + if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) + bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); + } + } + if ( coinaddr[0] != 0 ) + { + if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 ) + { + bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); + jaddistr(privkeyarray,waddr->wifstr); + } + else if ( smartaddress(myinfo,typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) + { + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeyarray,wifstr); + } + else printf("cant find (%s) in wallet\n",coinaddr); + } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); + } else printf("invalid txid/vout %d of %d\n",i,n); + } + } + return(privkeyarray); +} + +int32_t basilisk_rawtx_return(struct supernet_info *myinfo,int32_t height,struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +{ + char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; + if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) + { + privkeyarray = basilisk_privkeyarray(myinfo,rawtx->coin,vins); + if ( (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) + { + if ( lockinputs != 0 ) + { + //printf("lockinputs\n"); + iguana_RTunspentslock(myinfo,rawtx->coin,vins); + if ( (n= cJSON_GetArraySize(vins)) != 0 ) + { + bits256 txid; int32_t vout; + for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; + //rawtx->txbytes = calloc(1,rawtx->I.datalen); + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); + free(signedtx); + retval = 0; + } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll + free_json(privkeyarray); + } + return(retval); +} + +int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) +{ + char *retstr,*jsonstr,scriptstr[1024],coinaddr[64]; uint32_t basilisktag; int32_t flag,i,n,retval = -1; cJSON *addresses,*valsobj,*retarray=0; struct vin_info *V; + //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); + if ( rawtx->coin->changeaddr[0] == 0 ) + { + bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->chain->pubtype,pubkey33,33); + printf("set change address.(%s)\n",rawtx->coin->changeaddr); + } + init_hexbytes_noT(scriptstr,script,scriptlen); + basilisktag = (uint32_t)rand(); + valsobj = cJSON_CreateObject(); + jaddstr(valsobj,"coin",rawtx->coin->symbol); + jaddstr(valsobj,"spendscript",scriptstr); + jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); + jadd64bits(valsobj,"satoshis",rawtx->I.amount); + if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) + txfee = 50000; + jadd64bits(valsobj,"txfee",txfee); + jaddnum(valsobj,"minconf",minconf); + if ( locktime == 0 ) + locktime = (uint32_t)time(NULL) - 777; + jaddnum(valsobj,"locktime",locktime); + jaddnum(valsobj,"timeout",30000); + jaddnum(valsobj,"timestamp",swapstarted+delay); + addresses = cJSON_CreateArray(); + bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,pubkey33,33); + jaddistr(addresses,coinaddr); + jadd(valsobj,"addresses",addresses); + rawtx->I.locktime = locktime; + printf("%s locktime.%u\n",rawtx->name,locktime); + V = calloc(256,sizeof(*V)); + if ( (retstr= basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V)) != 0 ) + { + printf("%s %s basilisk_bitcoinrawtx.(%s) txfee %.8f\n",rawtx->name,str,retstr,dstr(txfee)); + flag = 0; + if ( (retarray= cJSON_Parse(retstr)) != 0 ) + { + if ( is_cJSON_Array(retarray) != 0 ) + { + n = cJSON_GetArraySize(retarray); + for (i=0; icoin->longestchain,rawtx,jitem(retarray,i),lockinputs,V)) == 0 ) + { + rawtx->vins = jduplicate(jobj(jitem(retarray,i),"vins")); + jsonstr = jprint(rawtx->vins,0); + safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); + free(jsonstr); + break; + } + } + } + else + { + retval = basilisk_rawtx_return(myinfo,rawtx->coin->longestchain,rawtx,retarray,lockinputs,V); + rawtx->vins = jduplicate(jobj(retarray,"vins")); + jsonstr = jprint(rawtx->vins,0); + safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); + free(jsonstr); + } + free(retarray); + } else printf("error parsing.(%s)\n",retstr); + free(retstr); + } else printf("error creating %s %s\n",iambob != 0 ? "BOB" : "ALICE",rawtx->name); + free_json(valsobj); + free(V); + return(retval); +} + +int32_t basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) +{ + int32_t retval,len; uint64_t newtxfee; struct iguana_info *coin; + if ( (coin= rawtx->coin) == 0 || strcmp(coin->symbol,"BTC") != 0 ) + return(_basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay)); + retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,0,rawtx,locktime,script,scriptlen,txfee,minconf,delay); + len = rawtx->I.datalen; + if ( coin->estimatedfee == 0 ) + coin->estimatedfee = iguana_getestimatedfee(myinfo,coin); + newtxfee = coin->estimatedfee * len; + if ( newtxfee > txfee ) + { + retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,newtxfee,minconf,delay); + printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); + } + return(retval); +} diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c new file mode 100644 index 000000000..d15ea3f47 --- /dev/null +++ b/iguana/exchanges/LP_commands.c @@ -0,0 +1,105 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_commands.c +// marketmaker +// + +void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +{ + char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid; struct LP_utxoinfo *utxo; + if ( (method= jstr(argjson,"method")) != 0 ) + { + if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) + { + txid = jbits256(argjson,"txid"); + if ( (utxo= LP_utxofind(txid)) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && utxo->swappending == 0 ) + { + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + { + if ( (price= LP_price(base,rel)) != 0. ) + { + price *= (1. + profitmargin); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",base); + jaddstr(retjson,"rel",rel); + jaddnum(retjson,"timestamp",time(NULL)); + jaddnum(retjson,"price",price); + jaddbits256(retjson,"txid",txid); + jadd64bits(retjson,"destsatoshis",price * utxo->satoshis); + if ( strcmp(method,"request") == 0 ) + { + utxo->swappending = (uint32_t)(time(NULL) + 60); + utxo->otherpubkey = jbits256(argjson,"pubkey"); + jaddnum(retjson,"pending",utxo->swappending); + } + retstr = jprint(retjson,1); + LP_send(pubsock,retstr,1); + } + } + } + } + else if ( ) + { + + } + } +} + +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port +{ + char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + if ( (method= jstr(argjson,"method")) == 0 ) + return(clonestr("{\"error\":\"need method in request\"}")); + else + { + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + { + if ( (pushport= juint(argjson,"push")) == 0 ) + pushport = argport + 1; + if ( (subport= juint(argjson,"sub")) == 0 ) + subport = argport + 2; + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + peer->numpeers = otherpeers; + if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + { + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); + peer->numutxos = othernumutxos; + } + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( strcmp(method,"notifyutxo") == 0 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } + } else printf("malformed request.(%s)\n",jprint(argjson,0)); + } + if ( retstr != 0 ) + return(retstr); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"error","unrecognized command"); + return(clonestr(jprint(retjson,1))); +} diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_nativeDEX.c similarity index 88% rename from iguana/exchanges/LP_unspents.c rename to iguana/exchanges/LP_nativeDEX.c index 15982d0d3..f139d12ac 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -1,17 +1,29 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ // // LP_unspents.c // marketmaker // -// Created by Mac on 5/23/17. -// Copyright © 2017 SuperNET. All rights reserved. -// #include #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; -portable_mutex_t LP_peermutex,LP_utxomutex,LP_jsonmutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex; int32_t LP_mypubsock = -1; struct LP_peerinfo @@ -28,9 +40,10 @@ struct LP_peerinfo struct LP_utxoinfo { UT_hash_handle hh; - bits256 txid,deposittxid; + bits256 txid,deposittxid,otherpubkey; + void *swap; uint64_t satoshis,depositsatoshis; - int32_t vout,depositvout; uint32_t lasttime,errors; + int32_t vout,depositvout; uint32_t lasttime,errors,swappending; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; @@ -512,59 +525,17 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin return(total); } -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) -{ - char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; - if ( (method= jstr(argjson,"method")) == 0 ) - return(clonestr("{\"error\":\"need method in request\"}")); - else - { - portable_mutex_lock(&LP_jsonmutex); - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - { - if ( (pushport= juint(argjson,"push")) == 0 ) - pushport = argport + 1; - if ( (subport= juint(argjson,"sub")) == 0 ) - subport = argport + 2; - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { - if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) - peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) - { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); - peer->numutxos = othernumutxos; - } - //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - else if ( strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"notifyutxo") == 0 ) - { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); - } - } else printf("malformed request.(%s)\n",jprint(argjson,0)); - portable_mutex_unlock(&LP_jsonmutex); - } - if ( retstr != 0 ) - return(retstr); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"error","unrecognized command"); - return(clonestr(jprint(retjson,1))); -} +#include "LP_bitcoin.c" +#include "LP_swap.c" +#include "LP_remember.c" +#include "LP_commands.c" void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0,*retstr; long filesize,n; int32_t timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; + char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); - portable_mutex_init(&LP_jsonmutex); + portable_mutex_init(&LP_commandmutex); if ( profitmargin == 0. ) { profitmargin = 0.01; @@ -651,11 +622,13 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { + portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } + portable_mutex_unlock(&LP_commandmutex); free_json(argjson); } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) @@ -665,7 +638,14 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - printf("PULL.[%d] %s\n",recvsize,(char *)ptr); + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + len = (int32_t)strlen((char *)ptr) + 1; + portable_mutex_lock(&LP_commandmutex); + LP_command(mypeer,mypub,argjson,&ptr[len],recvsize - len,profitmargin); + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c new file mode 100644 index 000000000..691325cc4 --- /dev/null +++ b/iguana/exchanges/LP_prices.c @@ -0,0 +1,41 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_prices.c +// marketmaker +// + +double LP_kmdbtc; + +// very, very simple for now + +void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]) +{ + if ( avebid > SMALLVAL && aveask > SMALLVAL && strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) + LP_kmdbtc = (avebid + aveask) * 0.5; +} + +double LP_price(char *base,char *rel) +{ + if ( LP_kmdbtc != 0. ) + { + if ( strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) + return(LP_kmdbtc); + else if ( strcmp(rel,"KMD") == 0 && strcmp(base,"BTC") == 0 ) + return(1. / LP_kmdbtc); + } + return(0.); +} diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c new file mode 100644 index 000000000..22ec7d53a --- /dev/null +++ b/iguana/exchanges/LP_remember.c @@ -0,0 +1,1168 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_remember.c +// marketmaker +// + + +cJSON *basilisk_nullretjson(cJSON *retjson) +{ + char *outstr; + if ( retjson != 0 ) + { + outstr = jprint(retjson,0); + if ( strcmp(outstr,"{}") == 0 ) + { + free_json(retjson); + retjson = 0; + } + free(outstr); + } + return(retjson); +} + +cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) + { + //printf("dexgettxout.(%s)\n",retstr); + retjson = cJSON_Parse(retstr); + free(retstr); + } + if ( 0 && strcmp("BTC",symbol) == 0 ) + printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); + } + else + { + retjson = dpow_gettxout(myinfo,coin,trigger,vout); + //printf("need to verify passthru has this info\n"); + //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); + } + return(basilisk_nullretjson(retjson)); +} + +cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettransaction(myinfo,0,0,0,txid,symbol)) != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + //if ( strcmp("BTC",symbol) == 0 ) + // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); + } else retjson = dpow_gettransaction(myinfo,coin,txid); + return(basilisk_nullretjson(retjson)); +} + +int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON *txobj) +{ + int32_t n,m,retval = -1; cJSON *vouts,*item,*addresses,*skey; char *addr; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) + { + item = jitem(vouts,vout); + if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(destaddr,addr,64); + retval = 0; + } + //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); + } + } + return(retval); +} + +int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) +{ + cJSON *retjson; + coinaddr[0] = 0; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + basilisk_swap_txdestaddr(coinaddr,txid,vout,retjson); + free_json(retjson); + } + return(coinaddr[0] != 0); +} + +int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) +{ + cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) + { + item = jitem(vins,vini); + if ( (skey= jobj(item,"scriptSig")) != 0 && (hexstr= jstr(skey,"hex")) != 0 && (scriptlen= (int32_t)strlen(hexstr)) < maxlen*2 ) + { + scriptlen >>= 1; + decode_hex(script,scriptlen,hexstr); + //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + } + } + free_json(retjson); + } + return(scriptlen); +} + +int64_t basilisk_txvalue(struct supernet_info *myinfo,char *symbol,bits256 txid,int32_t vout) +{ + cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; + //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); + if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + //printf("txobj.(%s)\n",jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) + { + item = jitem(vouts,vout); + if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(item,"value") * SATOSHIDEN; + } + free_json(txobj); + } + return(value); +} + +bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) +{ + char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; + memset(&spendtxid,0,sizeof(spendtxid)); + if ( (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i %s\n",bits256_str(str,spendtxid),destaddr); + break; + } + } + } + } + free_json(array); + } + free(retstr); + } + return(spendtxid); +} + +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +{ + bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; struct iguana_info *coin = iguana_coinfind(symbol); + // listtransactions or listspents + destaddr[0] = 0; + coinaddr[0] = 0; + memset(&spendtxid,0,sizeof(spendtxid)); + //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); + if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 ) + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + } + else if ( coin != 0 ) + { + if ( (array= dpow_listtransactions(myinfo,coin,destaddr,1000,0)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i jint(item,"vout") ) + { + item2 = jitem(vins,jint(item,"vout")); + if ( bits256_cmp(utxotxid,jbits256(item2,"txid")) == 0 && vout == jint(item2,"vout") ) + { + spendtxid = txid; + break; + } + } + } + } + } + if ( i == n ) + printf("dpowlist: native couldnt find spendtxid for %s\n",bits256_str(str,utxotxid)); + } + free_json(array); + } + if ( bits256_nonz(spendtxid) != 0 ) + return(spendtxid); + } + if ( iguana_isnotarychain(symbol) >= 0 ) + { + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); + if ( coinaddr[0] != 0 ) + { + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + printf("spendtxid.(%s)\n",bits256_str(str,spendtxid)); + } + } + } + return(spendtxid); +} + +bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) +{ + char *retstr; bits256 txid; int32_t i,sentflag = 0; + memset(&txid,0,sizeof(txid)); + for (i=0; i<3; i++) + { + if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + sentflag = 1; + } + char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + free(retstr); + } + if ( sentflag != 0 ) + break; + } + return(txid); +} + +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) +{ + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + *destamountp = 0; + if ( finalseqid == 0 ) + locktime = expiration; + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) + return(0); + if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + { + printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); + return(0); + } + if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); + free_json(utxoobj); + return(0); + } else free_json(utxoobj); + *destamountp = destamount; + if ( destamount > 10000 ) + destamount -= 10000; + if ( strcmp(symbol,"BTC") == 0 ) + { + if ( destamount > 40000 ) + destamount -= 40000; + } + height = coin->longestchain; + timestamp = (uint32_t)time(NULL); + V = calloc(256,sizeof(*V)); + privkeys = cJSON_CreateArray(); + if ( privkey2p != 0 ) + { + V[0].signers[1].privkey = *privkey2p; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2p); + bitcoin_priv2wif(wifstr,*privkey2p,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + } else V[0].N = V[0].M = 1; + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].suppress_pubkeys = suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( redeemlen != 0 ) + memcpy(V[0].p2shscript,redeemscript,redeemlen), V[0].p2shlen = redeemlen; + txobj = bitcoin_txcreate(coin->symbol,coin->chain->isPoS,locktime,1,timestamp); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); + } + jaddbits256(item,"txid",utxotxid); + jaddnum(item,"vout",vout); + sobj = cJSON_CreateObject(); + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + /*int32_t i; + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" pubkey33 ->\n"); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" destaddr.(%s)\n",destaddr); + calc_rmd160_sha256(rmd160,pubkey33,33); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- vs direct calc\n");*/ + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + init_hexbytes_noT(hexstr,spendscript,spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( redeemlen != 0 ) + { + init_hexbytes_noT(hexstr,redeemscript,redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); + if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) + { + //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + printf("couldnt sign transaction\n"); + else if ( completed == 0 ) + printf("incomplete signing\n"); + else printf("%s -> %s\n",name,bits256_str(str,signedtxid)); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(signedtx); +} + +char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) +{ + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); + pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); + //char str[65]; + //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); + //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); + spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); + //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); + /*rev = privAm; + for (i=0; i<32; i++) + privAm.bytes[i] = rev.bytes[31 - i]; + rev = privBn; + for (i=0; i<32; i++) + privBn.bytes[i] = rev.bytes[31 - i];*/ + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); + } + return(signedtx); +} + +bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) +{ + bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit + memset(&privkey,0,sizeof(privkey)); + if ( (scriptlen= basilisk_swap_getsigscript(myinfo,symbol,script,(int32_t)sizeof(script),spendtxid,vini)) > 0 ) + { + siglen = script[0]; + for (i=0; i<32; i++) + { + if ( revflag != 0 ) + privkey.bytes[31 - i] = script[siglen+2+i]; + else privkey.bytes[i] = script[siglen+2+i]; + } + char str[65]; printf("extracted privbob.(%s)\n",bits256_str(str,privkey)); + } + return(privkey); +} + +bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn) +{ + char destaddr[64]; + if ( bits256_nonz(privBn) == 0 ) + { + if ( bits256_nonz(bobdeposit) != 0 ) + *bobrefundp = basilisk_swap_spendtxid(myinfo,bobcoin,destaddr,bobdeposit,0); + if ( bits256_nonz(*bobrefundp) != 0 ) + privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0,0); + } + return(privBn); +} + +bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) +{ + bits256 spendtxid,txid; char destaddr[64]; + txid = txids[utxoind]; + memset(&spendtxid,0,sizeof(spendtxid)); + /*if ( aliceaddr != 0 ) + printf("aliceaddr.(%s)\n",aliceaddr); + if ( bobaddr != 0 ) + printf("bobaddr.(%s)\n",bobaddr);*/ + if ( bits256_nonz(txid) != 0 ) + { + //char str[65]; + spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); + if ( bits256_nonz(spendtxid) != 0 ) + { + sentflags[utxoind] = 1; + if ( aliceaddr != 0 && strcmp(destaddr,aliceaddr) == 0 ) + { + //printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; + } + else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) + { + //printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; + } + else + { + //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + if ( aliceaddr != 0 ) + { + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; + } + else if ( bobaddr != 0 ) + { + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; + } + } + } + } else printf("utxoind.%d null txid\n",utxoind); + return(spendtxid); +} + +#define BASILISK_ALICESPEND 0 +#define BASILISK_BOBSPEND 1 +#define BASILISK_BOBPAYMENT 2 +#define BASILISK_ALICEPAYMENT 3 +#define BASILISK_BOBDEPOSIT 4 +#define BASILISK_OTHERFEE 5 +#define BASILISK_MYFEE 6 +#define BASILISK_BOBREFUND 7 +#define BASILISK_BOBRECLAIM 8 +#define BASILISK_ALICERECLAIM 9 +#define BASILISK_ALICECLAIM 10 +//0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 +char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; + +int32_t basilisk_isbobcoin(int32_t iambob,int32_t ind) +{ + switch ( ind ) + { + case BASILISK_MYFEE: return(iambob); break; + case BASILISK_OTHERFEE: return(!iambob); break; + case BASILISK_BOBSPEND: + case BASILISK_ALICEPAYMENT: + case BASILISK_ALICERECLAIM: + case BASILISK_ALICECLAIM: return(0); + break; + case BASILISK_BOBDEPOSIT: + case BASILISK_ALICESPEND: + case BASILISK_BOBPAYMENT: + case BASILISK_BOBREFUND: + case BASILISK_BOBRECLAIM: return(1); + break; + default: return(-1); break; + } +} + +// add blocktrail presence requirement for BTC +int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) +{ + int32_t i,n = 0; + for (i=0; i (%s)\n",fname,fstr); + if ( (txobj= cJSON_Parse(fstr)) != 0 ) + { + paymentspent = jbits256(txobj,"paymentspent"); + Apaymentspent = jbits256(txobj,"Apaymentspent"); + depositspent = jbits256(txobj,"depositspent"); + if ( (array= jarray(&n,txobj,"values")) != 0 ) + for (i=0; i (%s)\n",fname,fstr); + if ( (txobj= cJSON_Parse(fstr)) != 0 ) + { + //printf("TXOBJ.(%s)\n",jprint(txobj,0)); + iambob = jint(txobj,"iambob"); + txid = jbits256(txobj,"txid"); + if ( bits256_nonz(txid) == 0 ) + continue; + txids[i] = txid; + if ( jobj(txobj,"tx") != 0 ) + { + txbytes[i] = clonestr(jstr(txobj,"tx")); + //printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); + } + if ( (value= jdouble(txobj,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(txobj,"value") * SATOSHIDEN; + values[i] = value; + if ( (symbol= jstr(txobj,"coin")) != 0 ) + { + if ( i == BASILISK_ALICESPEND || i == BASILISK_BOBPAYMENT || i == BASILISK_BOBDEPOSIT || i == BASILISK_BOBREFUND || i == BASILISK_BOBRECLAIM || i == BASILISK_ALICECLAIM ) + safecopy(bobcoin,symbol,sizeof(bobcoin)); + else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) + safecopy(alicecoin,symbol,sizeof(alicecoin)); + if ( finishedflag == 0 ) + { + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } + else + { + checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); + if ( bits256_cmp(checktxid,txid) == 0 ) + { + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; + } + free_json(sentobj); + } + printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); + } + } + } //else printf("no symbol\n"); + free(fstr); + } else if ( finishedflag == 0 ) + printf("%s not finished\n",fname); + } + //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); + Adestaddr[0] = destaddr[0] = 0; + Adest = Bdest = AAdest = ABdest = 0; + if ( bobcoin[0] == 0 || alicecoin[0] == 0 ) + return(0); + //printf("privAm.(%s) %p/%p\n",bits256_str(str,privAm),Adest,AAdest); + //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); + if ( finishedflag == 0 && bobcoin[0] != 0 && alicecoin[0] != 0 ) + { + if ( iambob == 0 ) + { + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + AAdest = Adestaddr; + } + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Adest = destaddr; + } + } + else + { + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Bdest = destaddr; + } + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + ABdest = Adestaddr; + } + } + if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) + { + printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); + if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + { + sentflags[BASILISK_ALICEPAYMENT] = 1; + free_json(sentobj); + } + } + paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); + Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); + depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); + finishedflag = basilisk_swap_isfinished(iambob,txids,sentflags,paymentspent,Apaymentspent,depositspent); + if ( iambob == 0 ) + { + if ( sentflags[BASILISK_ALICESPEND] == 0 ) + { + if ( sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(paymentspent) == 0 ) + { + //if ( txbytes[BASILISK_ALICESPEND] == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) + { + // alicespend + for (j=0; j<32; j++) + rev.bytes[j] = privAm.bytes[31 - j]; + revcalc_rmd160_sha256(secretAm,rev);//privAm); + vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) + printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); + } + } + if ( txbytes[BASILISK_ALICESPEND] != 0 ) + { + txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested + { + sentflags[BASILISK_ALICESPEND] = 1; + paymentspent = txids[BASILISK_ALICESPEND]; + } + } + } + } + if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) + { + if ( time(NULL) > expiration ) + { + //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) + { + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,zero,secretAm,secretAm256,secretBn,secretBn256); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) + printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); + } + } + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + { + txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_ALICECLAIM] = 1; + depositspent = txids[BASILISK_ALICECLAIM]; + } + } + } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); + } + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 && bits256_nonz(Apaymentspent) == 0 && sentflags[BASILISK_ALICECLAIM] == 0 ) + { + //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) + { + privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); + if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) + printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); + } + } + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + { + txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_ALICERECLAIM] = 1; + Apaymentspent = txids[BASILISK_ALICERECLAIM]; + } + } + } + } + else if ( iambob == 1 ) + { + if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) + { + printf("try to bobspend aspend.%s have privAm.%d\n",bits256_str(str,txids[BASILISK_ALICESPEND]),bits256_nonz(privAm)); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) + { + //if ( txbytes[BASILISK_BOBSPEND] == 0 ) + { + if ( bits256_nonz(privAm) == 0 ) + { + privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0,1); + } + if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) + printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); + } + } + if ( txbytes[BASILISK_BOBSPEND] != 0 ) + { + txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested + { + sentflags[BASILISK_BOBSPEND] = 1; + Apaymentspent = txids[BASILISK_BOBSPEND]; + } + } + } + } + if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration && bits256_nonz(paymentspent) == 0 ) + { + //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) + { + // bobreclaim + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,zero,privBn,secretAm,secretAm256,secretBn,secretBn256); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) + { + int32_t z; + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm, myprivs[1].(%s) bobreclaim.(%s)\n",bits256_str(str,myprivs[1]),txbytes[BASILISK_BOBRECLAIM]); + } + } + } + if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + { + txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_BOBRECLAIM] = 1; + paymentspent = txids[BASILISK_BOBRECLAIM]; + } + } + } + if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) + { + if ( bits256_nonz(paymentspent) != 0 || time(NULL) > expiration ) + { + printf("do the refund!\n"); + //if ( txbytes[BASILISK_BOBREFUND] == 0 ) + { + revcalc_rmd160_sha256(secretBn,privBn); + vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) + printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); + } + if ( txbytes[BASILISK_BOBREFUND] != 0 ) + { + txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested + { + sentflags[BASILISK_BOBREFUND] = 1; + depositspent = txids[BASILISK_BOBREFUND]; + } + } + } else printf("time %u vs expiration %u\n",(uint32_t)time(NULL),expiration); + } + } + } + //printf("finish.%d iambob.%d REFUND %d %d %d %d\n",finishedflag,iambob,sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); + if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) + sentflags[BASILISK_BOBPAYMENT] = 1; + if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_BOBSPEND] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) + sentflags[BASILISK_BOBDEPOSIT] = 1; + for (i=0; inumswaps; i++) + if ( (swap= myinfo->swaps[i]) != 0 && swap->I.req.requestid == requestid && swap->I.req.quoteid == quoteid ) + { + jaddi(array,basilisk_swapjson(myinfo,swap)); + flag = 1; + break; + } + if ( flag == 0 ) + { + if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) + { + jaddi(array,item); + if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + break; + } + } + } + fclose(fp); + } + jaddstr(retjson,"result","success"); + jadd(retjson,"swaps",array); + if ( cJSON_GetArraySize(array) > 0 ) + { + totalsobj = cJSON_CreateObject(); + for (Btotal=i=0; i 0 && Btotal < 0 ) + jaddnum(retjson,"avebuy",(double)-Btotal/Ktotal); + else if ( Ktotal < 0 && Btotal > 0 ) + jaddnum(retjson,"avesell",(double)-Btotal/Ktotal); + } + array = cJSON_CreateArray(); + for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) + { + if ( myinfo->linfos[i].base[0] != 0 && myinfo->linfos[i].rel[0] != 0 ) + jaddi(array,linfo_json(&myinfo->linfos[i])); + } + jadd(retjson,"quotes",array); + return(jprint(retjson,1)); +} + diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c new file mode 100644 index 000000000..5df4a6b86 --- /dev/null +++ b/iguana/exchanges/LP_swap.c @@ -0,0 +1,2379 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_swap.c +// marketmaker +// +/* + resume handling: list of tx broadcast, tx pending + required items, reconnect state machine or have statemachine assume off by one or state/otherstate specific handling + make sure to broadcast deposit before claiming refund, or to just skip it if neither is done + */ + +#define DEX_SLEEP 10 +#define BASILISK_DEFAULT_NUMCONFIRMS 5 + +// Todo: monitor blockchains, ie complete extracting scriptsig +// mode to autocreate required outputs +// more better LP commands + +// depends on just three external functions: +// - basilisk_sendrawtransaction(myinfo,coin,signedtx); +// - basilisk_value(myinfo,rawtx->coin,0,0,myinfo->myaddr.persistent,argjson,0) +// basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V) + + +// included from basilisk.c +/* https://bitcointalk.org/index.php?topic=1340621.msg13828271#msg13828271 + https://bitcointalk.org/index.php?topic=1364951 + Tier Nolan's approach is followed with the following changes: + a) instead of cutting 1000 keypairs, only INSTANTDEX_DECKSIZE are a + b) instead of sending the entire 256 bits, it is truncated to 64 bits. With odds of collision being so low, it is dwarfed by the ~0.1% insurance factor. + c) D is set to ~100x the insurance rate of 1/777 12.87% + BTC amount + d) insurance is added to Bob's payment, which is after the deposit and bailin + e) BEFORE Bob broadcasts deposit, Alice broadcasts BTC denominated fee in cltv so if trade isnt done fee is reclaimed + */ + +//#define DISABLE_CHECKSIG // unsolved MITM (evil peer) + +/* + both fees are standard payments: OP_DUP OP_HASH160 FEE_RMD160 OP_EQUALVERIFY OP_CHECKSIG + + Alice altpayment: OP_2 OP_2 OP_CHECKMULTISIG + + Bob deposit: + #ifndef DISABLE_CHECKSIG + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF + #else + OP_IF + OP_CLTV OP_DROP OP_SHA256 OP_EQUAL + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_SHA256 OP_EQUAL + OP_ENDIF + #endif + + Bob paytx: + #ifndef DISABLE_CHECKSIG + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF + #else + OP_IF + OP_CLTV OP_DROP OP_SHA256 OP_EQUAL + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_SHA256 OP_EQUAL + OP_ENDIF + #endif + + Naming convention are pubAi are alice's pubkeys (seems only pubA0 and not pubA1) + pubBi are Bob's pubkeys + + privN is Bob's privkey from the cut and choose deck as selected by Alice + privM is Alice's counterpart + pubN and pubM are the corresponding pubkeys for these chosen privkeys + + Alice timeout event is triggered if INSTANTDEX_LOCKTIME elapses from the start of a FSM instance. Bob timeout event is triggered after INSTANTDEX_LOCKTIME*2 + */ + +/* + Bob sends bobdeposit and waits for alicepayment to confirm before sending bobpayment + Alice waits for bobdeposit to confirm and sends alicepayment + + Alice spends bobpayment immediately divulging privAm + Bob spends alicepayment immediately after getting privAm and divulges privBn + + Bob will spend bobdeposit after end of trade or INSTANTDEX_LOCKTIME, divulging privBn + Alice spends alicepayment as soon as privBn is seen + + Bob will spend bobpayment after INSTANTDEX_LOCKTIME + Alice spends bobdeposit in 2*INSTANTDEX_LOCKTIME + */ + +//Bobdeposit includes a covered put option for alicecoin, duration INSTANTDEX_LOCKTIME +//alicepayment includes a covered call option for alicecoin, duration (2*INSTANTDEX_LOCKTIME - elapsed) + + +/* in case of following states, some funds remain unclaimable, but all identified cases are due to one or both sides not spending when they were the only eligible party: + + Bob failed to claim deposit during exclusive period and since alice put in the claim, the alicepayment is unspendable. if alice is nice, she can send privAm to Bob. + Apaymentspent.(0000000000000000000000000000000000000000000000000000000000000000) alice.0 bob.0 + paymentspent.(f91da4e001360b95276448e7b01904d9ee4d15862c5af7f5c7a918df26030315) alice.0 bob.1 + depositspent.(f34e04ad74e290f63f3d0bccb7d0d50abfa54eea58de38816fdc596a19767add) alice.1 bob.0 + + */ + +int32_t basilisk_istrustedbob(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + // for BTC and if trusted LP + return(0); +} + +struct basilisk_rawtx *basilisk_swapdata_rawtx(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) +{ + if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) + { + memcpy(data,rawtx->txbytes,rawtx->I.datalen); + return(rawtx); + } + return(0); +} + +int32_t basilisk_verify_otherfee(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + // add verification and broadcast + //swap->otherfee.txbytes = calloc(1,datalen); + memcpy(swap->otherfee.txbytes,data,datalen); + swap->otherfee.I.datalen = datalen; + swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); + basilisk_txlog(myinfo,swap,&swap->otherfee,-1); + return(0); +} + +int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) +{ + int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; + datalen = recvbuf[0]; + datalen += (int32_t)recvbuf[1] << 8; + if ( datalen > 65536 ) + return(-1); + rawtx->I.redeemlen = recvbuf[2]; + data = &recvbuf[3]; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); + //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); + if ( rawtx->I.datalen == 0 ) + { + //rawtx->txbytes = calloc(1,datalen); + memcpy(rawtx->txbytes,data,datalen); + rawtx->I.datalen = datalen; + } + else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) + { + int32_t i; for (i=0; iI.datalen; i++) + printf("%02x",rawtx->txbytes[i]); + printf(" <- rawtx\n"); + printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); + return(-1); + } + txid = bits256_doublesha256(0,data,datalen); + char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + rawtx->I.actualtxid = txid; + if ( (txobj= bitcoin_data2json(rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + rawtx->I.actualtxid = rawtx->I.signedtxid; + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); + rawtx->I.locktime = rawtx->msgtx.lock_time; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) + { + vout = jitem(vouts,v); + if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) + { + if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) + { + decode_hex(rawtx->spendscript,hexlen,hexstr); + rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->chain->p2shtype,rawtx->spendscript,hexlen); + if ( swap != 0 ) + basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment + retval = 0; + } + } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); + } + free_json(txobj); + } + return(retval); +} + +void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) +{ + cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; + if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + { + vout = jitem(vouts,0); + //printf("VOUT.(%s)\n",jprint(vout,0)); + if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + //printf("extracted.(%s)\n",coinaddr); + } + } + } + free_json(txobj); + } +} + +int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,bits256 signpriv,uint8_t *redeemscript,int32_t redeemlen) +{ + int32_t i,len = 0; +#ifdef DISABLE_CHECKSIG + userdata[len++] = sizeof(signpriv); + for (i=0; i if path, 0 -> else path + return(len); +} + +/* Bob deposit: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) +{ + int32_t i; char scriptstr[513]; + if ( scriptlen != 0 ) + { + for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); + coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; + memset(zeroes,0,sizeof(zeroes)); + if ( rawtx != 0 && (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); + if ( rawtx->I.datalen > 0 ) + { + fprintf(fp,",\"tx\":\""); + for (i=0; iI.datalen; i++) + fprintf(fp,"%02x",rawtx->txbytes[i]); + fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); + if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) + { + basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); + if ( coinaddr[0] != 0 ) + { + if ( swap->bobcoin != 0 && swap->bobcoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->bobcoin,coinaddr)) != 0 ) + free(tmp); + } + if ( rawtx == &swap->bobdeposit ) + safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); + else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); + } + } + } + if ( swap->Bdeposit[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); + if ( swap->Bpayment[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); + fprintf(fp,",\"expiration\":%u",swap->I.expiration); + fprintf(fp,",\"iambob\":%d",swap->I.iambob); + fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); + fprintf(fp,",\"alicecoin\":\"%s\"",swap->alicecoin->symbol); + fprintf(fp,",\"lock\":%u",locktime); + fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); + if ( bits256_nonz(triggertxid) != 0 ) + fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicecoin != 0 && swap->alicecoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->alicecoin,coinaddr)) != 0 ) + free(tmp); + } + fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); + } + /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); + basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); + basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); + basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen);*/ + fprintf(fp,"}\n"); + fclose(fp); + } + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + if ( memcmp(zeroes,swap->I.secretAm,20) != 0 ) + { + init_hexbytes_noT(secretAmstr,swap->I.secretAm,20); + fprintf(fp,",\"secretAm\":\"%s\"",secretAmstr); + } + if ( memcmp(zeroes,swap->I.secretAm256,32) != 0 ) + { + init_hexbytes_noT(secretAm256str,swap->I.secretAm256,32); + fprintf(fp,",\"secretAm256\":\"%s\"",secretAm256str); + } + if ( memcmp(zeroes,swap->I.secretBn,20) != 0 ) + { + init_hexbytes_noT(secretBnstr,swap->I.secretBn,20); + fprintf(fp,",\"secretBn\":\"%s\"",secretBnstr); + } + if ( memcmp(zeroes,swap->I.secretBn256,32) != 0 ) + { + init_hexbytes_noT(secretBn256str,swap->I.secretBn256,32); + fprintf(fp,",\"secretBn256\":\"%s\"",secretBn256str); + } + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + if ( bits256_nonz(swap->I.pubA0) != 0 ) + fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); + if ( bits256_nonz(swap->I.pubB0) != 0 ) + fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); + if ( bits256_nonz(swap->I.pubB1) != 0 ) + fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); + if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); + if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) + fprintf(fp,",\"Brefund\":\"%s\"",bits256_str(str,swap->bobrefund.I.actualtxid)); + if ( bits256_nonz(swap->aliceclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Aclaim\":\"%s\"",bits256_str(str,swap->aliceclaim.I.actualtxid)); + + if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",bits256_str(str,swap->bobpayment.I.actualtxid)); + if ( bits256_nonz(swap->alicespend.I.actualtxid) != 0 ) + fprintf(fp,",\"Aspend\":\"%s\"",bits256_str(str,swap->alicespend.I.actualtxid)); + if ( bits256_nonz(swap->bobreclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Breclaim\":\"%s\"",bits256_str(str,swap->bobreclaim.I.actualtxid)); + + if ( bits256_nonz(swap->alicepayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Apayment\":\"%s\"",bits256_str(str,swap->alicepayment.I.actualtxid)); + if ( bits256_nonz(swap->bobspend.I.actualtxid) != 0 ) + fprintf(fp,",\"Bspend\":\"%s\"",bits256_str(str,swap->bobspend.I.actualtxid)); + if ( bits256_nonz(swap->alicereclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Areclaim\":\"%s\"",bits256_str(str,swap->alicereclaim.I.actualtxid)); + + if ( bits256_nonz(swap->otherfee.I.actualtxid) != 0 ) + fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); + if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) + fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); + fprintf(fp,",\"dest33\":\""); + for (i=0; i<33; i++) + fprintf(fp,"%02x",swap->persistent_pubkey33[i]); + fprintf(fp,"\"}\n"); + fclose(fp); + } +} + +void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + bits256 triggertxid; + memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == 0 ) + { + basilisk_dontforget(myinfo,swap,0,0,triggertxid); + return; + } + if ( rawtx == &swap->myfee ) + basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); + else if ( rawtx == &swap->otherfee ) + basilisk_dontforget(myinfo,swap,&swap->otherfee,0,triggertxid); + else if ( rawtx == &swap->bobdeposit ) + { + basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + } + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + else if ( rawtx == &swap->aliceclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->alicepayment ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + } + else if ( rawtx == &swap->bobspend ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); + } + else if ( rawtx == &swap->alicereclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->bobpayment ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + } + else if ( rawtx == &swap->alicespend ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); + } + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); +} + +int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) + { + swap->bobdeposit.I.signedtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) + swap->depositunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobdeposit.I.datalen; i++) + printf("%02x",swap->bobdeposit.txbytes[i]); + printf(" <- bobdeposit\n"); + for (i=0; ialiceclaim.I.datalen; i++) + printf("%02x",swap->aliceclaim.txbytes[i]); + printf(" <- aliceclaim\n"); + basilisk_txlog(myinfo,swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); + return(retval); + } + } + printf("error with bobdeposit\n"); + return(-1); +} + +int32_t basilisk_bobdeposit_refund(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; + len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_bobrefund,userdata,len); + swap->I.userdata_bobrefundlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) + { + for (i=0; ibobrefund.I.datalen; i++) + printf("%02x",swap->bobrefund.txbytes[i]); + printf(" <- bobrefund.(%s)\n",bits256_str(str,swap->bobrefund.I.txid)); + basilisk_txlog(myinfo,swap,&swap->bobrefund,delay); + return(retval); + } + return(-1); +} + +/*Bob paytx: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +int32_t basilisk_bobpayment_reclaim(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; + printf("basilisk_bobpayment_reclaim\n"); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_bobreclaim,userdata,len); + swap->I.userdata_bobreclaimlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobreclaim.I.datalen; i++) + printf("%02x",swap->bobreclaim.txbytes[i]); + printf(" <- bobreclaim\n"); + basilisk_txlog(myinfo,swap,&swap->bobreclaim,delay); + return(retval); + } + return(-1); +} + +int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; struct basilisk_swap *swap = ptr; + memset(revAm.bytes,0,sizeof(revAm)); + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) + { + swap->bobpayment.I.signedtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) + swap->paymentunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); + for (i=0; i<32; i++) + revAm.bytes[i] = swap->I.privAm.bytes[31-i]; + len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_alicespend,userdata,len); + swap->I.userdata_alicespendlen = len; + char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobpayment.I.datalen; i++) + printf("%02x",swap->bobpayment.txbytes[i]); + printf(" <- bobpayment\n"); + for (i=0; ialicespend.I.datalen; i++) + printf("%02x",swap->alicespend.txbytes[i]); + printf(" <- alicespend\n\n"); + swap->I.alicespent = 1; + basilisk_txlog(myinfo,swap,&swap->alicespend,-1); + return(retval); + } + } + return(-1); +} + +void basilisk_alicepayment(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) +{ + alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->chain->p2shtype,pubAm,pubBn); + basilisk_rawtx_gen("alicepayment",myinfo,swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->chain->txfee,1,0); +} + +int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *dest) +{ + int32_t i,retval; + printf("alicepayment_spend\n"); + swap->alicepayment.I.spendlen = basilisk_alicescript(swap->alicepayment.redeemscript,&swap->alicepayment.I.redeemlen,swap->alicepayment.spendscript,0,swap->alicepayment.I.destaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + printf("alicepayment_spend len.%d\n",swap->alicepayment.I.spendlen); + if ( swap->I.iambob == 0 ) + { + memcpy(swap->I.userdata_alicereclaim,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_alicereclaimlen = swap->alicepayment.I.spendlen; + } + else + { + memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; + } + if ( (retval= basilisk_rawtx_sign(myinfo,swap->alicecoin->longestchain,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) + { + for (i=0; iI.datalen; i++) + printf("%02x",dest->txbytes[i]); + printf(" <- msigspend\n\n"); + if ( dest == &swap->bobspend ) + swap->I.bobspent = 1; + basilisk_txlog(myinfo,swap,dest,0); // bobspend or alicereclaim + return(retval); + } + return(-1); +} + +int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) + { + swap->alicepayment.I.signedtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) + swap->aliceunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); + return(0); + } + else return(-1); +} + +int32_t basilisk_verify_pubpair(int32_t *wrongfirstbytep,struct basilisk_swap *swap,int32_t ind,uint8_t pub0,bits256 pubi,uint64_t txid) +{ + if ( pub0 != (swap->I.iambob ^ 1) + 0x02 ) + { + (*wrongfirstbytep)++; + printf("wrongfirstbyte[%d] %02x\n",ind,pub0); + return(-1); + } + else if ( swap->otherdeck[ind][1] != pubi.txid ) + { + printf("otherdeck[%d] priv ->pub mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][1],(long long)pubi.txid); + return(-1); + } + else if ( swap->otherdeck[ind][0] != txid ) + { + printf("otherdeck[%d] priv mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][0],(long long)txid); + return(-1); + } + return(0); +} + +int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) +{ + int32_t i,j; //char str[65]; + if ( genflag != 0 && swap->I.iambob == 0 ) + printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); + if ( depositflag == 0 ) + { + swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + //for (i=0; ibobpayment.redeemlen; i++) + // printf("%02x",swap->bobpayment.redeemscript[i]); + //printf(" <- bobpayment.%d\n",i); + if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen("payment",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->chain->txfee,1,0); + if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) + { + printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobpayment.I.datalen; j++) + printf("%02x",swap->bobpayment.txbytes[j]); + //printf(" <- bobpayment.%d\n",swap->bobpayment.datalen); + //for (j=0; jbobpayment.redeemlen; j++) + // printf("%02x",swap->bobpayment.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); + printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); + iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobpayment.vins); + basilisk_bobpayment_reclaim(myinfo,swap,swap->I.callduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + } + else + { + swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen("deposit",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->chain->txfee,1,0); + if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) + { + printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobdeposit.I.datalen; j++) + printf("%02x",swap->bobdeposit.txbytes[j]); + printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); + //for (j=0; jbobdeposit.redeemlen; j++) + // printf("%02x",swap->bobdeposit.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); + //printf("GENERATED BOB DEPOSIT\n"); + iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobdeposit.vins); + basilisk_bobdeposit_refund(myinfo,swap,swap->I.putduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + //for (i=0; ibobdeposit.redeemlen; i++) + // printf("%02x",swap->bobdeposit.redeemscript[i]); + //printf(" <- bobdeposit.%d\n",i); + } + return(0); +} + +int32_t basilisk_verify_privi(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t j,wrongfirstbyte,len = 0; bits256 privkey,pubi; char str[65],str2[65]; uint8_t secret160[20],pubkey33[33]; uint64_t txid; struct basilisk_swap *swap = ptr; + memset(privkey.bytes,0,sizeof(privkey)); + if ( datalen == sizeof(bits256) ) + { + for (j=0; j<32; j++) + privkey.bytes[j] = data[len++]; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + pubi = bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + if ( basilisk_verify_pubpair(&wrongfirstbyte,swap,swap->I.choosei,pubkey33[0],pubi,txid) == 0 ) + { + if ( swap->I.iambob != 0 ) + { + swap->I.privAm = privkey; + vcalc_sha256(0,swap->I.secretAm256,privkey.bytes,sizeof(privkey)); + printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + basilisk_bobscripts_set(myinfo,swap,0,1); + } + else + { + swap->I.privBn = privkey; + vcalc_sha256(0,swap->I.secretBn256,privkey.bytes,sizeof(privkey)); + printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); + } + basilisk_dontforget_update(myinfo,swap,0); + char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); + return(0); + } + } + return(-1); +} + +int32_t basilisk_process_swapverify(struct supernet_info *myinfo,void *ptr,int32_t (*internal_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) +{ + struct basilisk_swap *swap = ptr; + if ( internal_func != 0 ) + return((*internal_func)(myinfo,swap,data,datalen)); + else return(0); +} + +void basilisk_swapgotdata(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) +{ + int32_t i; struct basilisk_swapmessage *mp; + for (i=0; inummessages; i++) + if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) + return; + //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); + swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); + mp = &swap->messages[swap->nummessages++]; + mp->crc32 = crc32; + mp->srchash = srchash; + mp->desthash = desthash; + mp->msgbits = msgbits; + mp->quoteid = quoteid; + mp->data = malloc(datalen); + mp->datalen = datalen; + memcpy(mp->data,data,datalen); + if ( reinit == 0 && swap->fp != 0 ) + { + fwrite(mp,1,sizeof(*mp),swap->fp); + fwrite(data,1,datalen,swap->fp); + fflush(swap->fp); + } +} + +FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +{ + FILE *fp=0; /*char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) == 0 ) + { + if ( (fp= fopen(fname,"wb+")) != 0 ) + { + fwrite(privkey.bytes,1,sizeof(privkey),fp); + fwrite(rp,1,sizeof(*rp),fp); + fwrite(&statebits,1,sizeof(statebits),fp); + fwrite(&optionduration,1,sizeof(optionduration),fp); + fflush(fp); + } + } + else if ( reinit != 0 ) + { + }*/ + return(fp); +} + +int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) +{ + FILE *fp=0; char fname[512]; int32_t retval = -1; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && + fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && + fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && + fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) + retval = 0; + fclose(fp); + } + return(retval); +} + +struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit); + +void basilisk_swaps_init(struct supernet_info *myinfo) +{ + char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) + { + while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) + { + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + printf("%s\n",fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed + { + memset(&M,0,sizeof(M)); + swapcompleted = 1; + for (iter=0; iter<2; iter++) + { + if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && + fread(&R,1,sizeof(R),fp) == sizeof(R) && + fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && + fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) + { + while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) + { + M.data = 0; + //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); + if ( M.datalen < 100000 ) + { + M.data = malloc(M.datalen); + if ( fread(M.data,1,M.datalen,fp) == M.datalen ) + { + if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) + { + if ( iter == 1 ) + { + if ( swap == 0 ) + { + swap = basilisk_thread_start(myinfo,privkey,&R,statebits,optionduration,1); + swap->I.choosei = swap->I.otherchoosei = -1; + } + if ( swap != 0 ) + basilisk_swapgotdata(myinfo,swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); + } + } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("error reading M.datalen %d\n",M.datalen); + free(M.data), M.data = 0; + } + } + } + if ( swapcompleted != 0 ) + break; + rewind(fp); + } + } + } + } else myinfo->swapsfp = fopen(fname,"wb+"); +} + +void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp); + +int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen)) +{ + uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; + while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + swap->lasttime = (uint32_t)time(NULL); + memset(srchash.bytes,0,sizeof(srchash)); + memset(desthash.bytes,0,sizeof(desthash)); + //printf("gotmsg.[%d] crc.%x\n",size,crc32); + offset = 0; + for (i=0; i<32; i++) + srchash.bytes[i] = ptr[offset++]; + for (i=0; i<32; i++) + desthash.bytes[i] = ptr[offset++]; + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); + if ( size > offset ) + { + crc32 = calc_crc32(0,&ptr[offset],size-offset); + if ( size > offset ) + { + //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); + basilisk_swapgotdata(myinfo,swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + } + } + else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) + { + if ( swap->aborted == 0 ) + { + swap->aborted = (uint32_t)time(NULL); + printf("got abort signal from other side\n"); + } + } else printf("basilisk_swapget: got strange packet\n"); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + //char str[65],str2[65]; + for (i=0; inummessages; i++) + { + //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); + if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) + { + if ( swap->messages[i].msgbits == msgbits ) + { + if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) + { + printf("nothing received for a while from Bob, try new sockets\n"); + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + } + mp = &swap->messages[i]; + if ( msgbits != 0x80000000 ) + break; + } + } + } + if ( mp != 0 ) + retval = (*basilisk_verify_func)(myinfo,swap,mp->data,mp->datalen); + //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); + return(retval); +} + +uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) +{ + uint8_t *buf; int32_t sentbytes,offset=0,i; + buf = malloc(datalen + sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2); + for (i=0; i<32; i++) + buf[offset++] = swap->I.myhash.bytes[i]; + for (i=0; i<32; i++) + buf[offset++] = swap->I.otherhash.bytes[i]; + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( datalen > 0 ) + memcpy(&buf[offset],data,datalen), offset += datalen; + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + printf("sentbytes.%d vs offset.%d\n",sentbytes,offset); + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) + nn_close(swap->pushsock), swap->pushsock = -1; //, + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = swap->I.iambob != 0 ? -1 : 0; + swap->aborted = (uint32_t)time(NULL); + } + } + //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); + free(buf); + return(nextbits); +} + +void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; + memset(buf,0,sizeof(buf)); + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + } + } else printf("basilisk_swap_sendabort\n"); +} + +int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + if ( basilisk_priviextract(myinfo,swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) + { + printf("extracted privBn from blockchain\n"); + } + else if ( basilisk_swapget(myinfo,swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) + { + } + if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) + { + char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); + return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); + } + return(-1); +} + +int32_t basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + if ( basilisk_priviextract(myinfo,swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) + { + printf("extracted privAm from blockchain\n"); + } + if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) + { + char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); + return(basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend)); + } + return(-1); +} + +bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) +{ + bits256 sharedsecret; + sharedsecret = curve25519_shared(privkey,orderhash); + vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); + return(bitcoin_pubkey33(ctx,pubkey,*newprivp)); +} + +int32_t instantdex_pubkeyargs(void *ctx,struct basilisk_swap *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) +{ + char buf[3]; int32_t i,n,m,len=0; bits256 pubi,reveal; uint64_t txid; uint8_t secret160[20],pubkey[33]; + sprintf(buf,"%c0",'A' - 0x02 + firstbyte); + if ( numpubs > 2 ) + { + if ( swap->I.numpubs+2 >= numpubs ) + return(numpubs); + //fprintf(stderr,">>>>>> start generating %s\n",buf); + } + for (i=n=m=0; iI.mypubs[n]) == 0 ) + { + swap->I.myprivs[n] = privkey; + memcpy(swap->I.mypubs[n].bytes,pubkey+1,sizeof(bits256)); + reveal = basilisk_revealkey(privkey,swap->I.mypubs[n]); + if ( swap->I.iambob != 0 ) + { + if ( n == 0 ) + swap->I.pubB0 = reveal; + else if ( n == 1 ) + swap->I.pubB1 = reveal; + } + else if ( swap->I.iambob == 0 ) + { + if ( n == 0 ) + swap->I.pubA0 = reveal; + else if ( n == 1 ) + swap->I.pubA1 = reveal; + } + } + } + if ( m < INSTANTDEX_DECKSIZE ) + { + swap->privkeys[m] = privkey; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); + m++; + if ( m > swap->I.numpubs ) + swap->I.numpubs = m; + } + n++; + } + if ( n > 2 || m > 2 ) + printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->I.numpubs); + return(n); +} + +void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33,int32_t jumblrflag) +{ + strcpy(rawtx->name,name); + rawtx->coin = coin; + strcpy(rawtx->I.coinstr,coin->symbol); + rawtx->I.numconfirms = numconfirms; + if ( (rawtx->I.amount= satoshis) < 50000 ) + rawtx->I.amount = 50000; + rawtx->I.vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit + rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit + if ( rawtx->I.vouttype == 0 ) + { + if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) + decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); + else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.rmd160,20); + } + if ( pubkey33 != 0 ) + { + memcpy(rawtx->I.pubkey33,pubkey33,33); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.pubkey33,33); + bitcoin_addr2rmd160(&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); + } + if ( rawtx->I.vouttype <= 1 && rawtx->I.destaddr[0] != 0 ) + { + rawtx->I.spendlen = bitcoin_standardspend(rawtx->spendscript,0,rawtx->I.rmd160); + printf("%s spendlen.%d %s <- %.8f\n",name,rawtx->I.spendlen,rawtx->I.destaddr,dstr(rawtx->I.amount)); + } else printf("%s vouttype.%d destaddr.(%s)\n",name,rawtx->I.vouttype,rawtx->I.destaddr); +} + +int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) +{ + struct iguana_info *coin = iguana_coinfind(src); + if ( coin == 0 || iguana_coinfind(dest) == 0 ) + return(0); + *bobcoinp = *alicecoinp = 0; + *bobcoinp = iguana_coinfind(dest); + *alicecoinp = iguana_coinfind(src); + if ( bits256_cmp(pubkey,srchash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(-1); + else return(0); + } + else if ( bits256_cmp(pubkey,desthash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(-1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(1); + else return(0); + } + return(0); +} + +void basilisk_swap_saveupdate(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + FILE *fp; char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(&swap->I,1,sizeof(swap->I),fp); + /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); + fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); + fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); + fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); + fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); + fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); + fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); + fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); + fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); + fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); + fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ + fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); + fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); + fwrite(swap->deck,1,sizeof(swap->deck),fp); + fclose(fp); + } +} + +int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) +{ + if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) + { + rawtx->coin = 0; + rawtx->vins = 0; + if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) + { + rawtx->coin = iguana_coinfind(rawtx->I.coinstr); + if ( rawtx->vinstr[0] != 0 ) + rawtx->vins = cJSON_Parse(rawtx->vinstr); + printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); + return(0); + } + } + return(-1); +} + +struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,int32_t reinit) +{ + FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t errs=0,jumblrflag,x = -1; + if ( reinit != 0 ) + { + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + printf("reinit.(%s)\n",fname); + if ( (fp= fopen(fname,"rb")) != 0 ) + { + if ( fread(&swap->I,1,sizeof(swap->I),fp) != sizeof(swap->I) ) + errs++; + if ( swap->bobcoin == 0 ) + swap->bobcoin = iguana_coinfind(swap->I.req.dest); + if ( swap->alicecoin == 0 ) + swap->alicecoin = iguana_coinfind(swap->I.req.src); + if ( swap->alicecoin != 0 && swap->bobcoin != 0 ) + { + /*basilisk_swap_loadtx(&swap->bobdeposit,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobpayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicepayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->myfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->otherfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->aliceclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicespend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobreclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobspend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobrefund,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicereclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol);*/ + } else printf("missing coins (%p %p)\n",swap->bobcoin,swap->alicecoin); + if ( fread(swap->privkeys,1,sizeof(swap->privkeys),fp) != sizeof(swap->privkeys) ) + errs++; + if ( fread(swap->otherdeck,1,sizeof(swap->otherdeck),fp) != sizeof(swap->otherdeck) ) + errs++; + if ( fread(swap->deck,1,sizeof(swap->deck),fp) != sizeof(swap->deck) ) + errs++; + fclose(fp); + } else printf("cant find.(%s)\n",fname); + } + else + { + swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; + if ( optionduration < 0 ) + swap->I.putduration -= optionduration; + else if ( optionduration > 0 ) + swap->I.callduration += optionduration; + swap->I.bobsatoshis = swap->I.req.destamount; + swap->I.alicesatoshis = swap->I.req.srcamount; + if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.bobinsurance = 50000; + if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.aliceinsurance = 50000; + strcpy(swap->I.bobstr,swap->I.req.dest); + strcpy(swap->I.alicestr,swap->I.req.src); + swap->I.started = (uint32_t)time(NULL); + swap->I.expiration = swap->I.req.timestamp + swap->I.putduration + swap->I.callduration; + OS_randombytes((uint8_t *)&swap->I.choosei,sizeof(swap->I.choosei)); + if ( swap->I.choosei < 0 ) + swap->I.choosei = -swap->I.choosei; + swap->I.choosei %= INSTANTDEX_DECKSIZE; + swap->I.otherchoosei = -1; + swap->I.myhash = pubkey25519; + if ( statebits != 0 ) + { + swap->I.iambob = 0; + swap->I.otherhash = swap->I.req.desthash; + } + else + { + swap->I.iambob = 1; + swap->I.otherhash = swap->I.req.srchash; + } + if ( bits256_nonz(privkey) == 0 || (x= instantdex_pubkeyargs(myinfo->ctx,swap,2 + INSTANTDEX_DECKSIZE,privkey,swap->I.orderhash,0x02+swap->I.iambob)) != 2 + INSTANTDEX_DECKSIZE ) + { + char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey)); + return(0); + } + } + swap->bobcoin = iguana_coinfind(swap->I.req.dest); + swap->alicecoin = iguana_coinfind(swap->I.req.src); + if ( swap->bobcoin == 0 || swap->alicecoin == 0 ) + { + printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",swap->bobcoin,swap->alicecoin,iguana_coinfind(swap->I.req.src),iguana_coinfind(swap->I.req.dest)); + free(swap); + return(0); + } + if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) + { + swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) + { + swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else + { + swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + } + /*if ( swap->I.bobconfirms == 0 ) + swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; + if ( swap->I.aliceconfirms == 0 ) + swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ + jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); + if ( swap->I.iambob != 0 ) + { + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + bobpub33 = pubkey33; + } + else + { + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + alicepub33 = pubkey33; + } + basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin->txfee,4,0,jumblrflag); + basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,bobpub33,jumblrflag); + swap->bobrefund.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,alicepub33,jumblrflag); + swap->aliceclaim.I.suppress_pubkeys = 1; + swap->aliceclaim.I.locktime = swap->I.started + swap->I.putduration+swap->I.callduration + 1; + + basilisk_rawtx_setparms("bobpayment",swap->I.req.quoteid,&swap->bobpayment,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + swap->bobcoin->txfee,3,0,jumblrflag); + basilisk_rawtx_setparms("alicespend",swap->I.req.quoteid,&swap->alicespend,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,alicepub33,jumblrflag); + swap->alicespend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("bobreclaim",swap->I.req.quoteid,&swap->bobreclaim,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,bobpub33,jumblrflag); + swap->bobreclaim.I.suppress_pubkeys = 1; + swap->bobreclaim.I.locktime = swap->I.started + swap->I.putduration + 1; + basilisk_rawtx_setparms("alicepayment",swap->I.req.quoteid,&swap->alicepayment,swap->alicecoin,swap->I.aliceconfirms,0,swap->I.alicesatoshis+swap->alicecoin->txfee,2,0,jumblrflag); + basilisk_rawtx_setparms("bobspend",swap->I.req.quoteid,&swap->bobspend,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,bobpub33,jumblrflag); + swap->bobspend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); + swap->alicereclaim.I.suppress_pubkeys = 1; + printf("IAMBOB.%d\n",swap->I.iambob); + + return(swap); +} +// end of alice/bob code + +void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) +{ + if ( rawtx->vins != 0 ) + free_json(rawtx->vins); + //if ( rawtx->txbytes != 0 ) + // free(rawtx->txbytes), rawtx->txbytes = 0; +} + +void basilisk_swap_finished(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + int32_t i; + swap->I.finished = (uint32_t)time(NULL); + // save to permanent storage + basilisk_rawtx_purge(&swap->bobdeposit); + basilisk_rawtx_purge(&swap->bobpayment); + basilisk_rawtx_purge(&swap->alicepayment); + basilisk_rawtx_purge(&swap->myfee); + basilisk_rawtx_purge(&swap->otherfee); + basilisk_rawtx_purge(&swap->aliceclaim); + basilisk_rawtx_purge(&swap->alicespend); + basilisk_rawtx_purge(&swap->bobreclaim); + basilisk_rawtx_purge(&swap->bobspend); + basilisk_rawtx_purge(&swap->bobrefund); + basilisk_rawtx_purge(&swap->alicereclaim); + for (i=0; inummessages; i++) + if ( swap->messages[i].data != 0 ) + free(swap->messages[i].data), swap->messages[i].data = 0; + free(swap->messages), swap->messages = 0; + swap->nummessages = 0; +} + +void basilisk_swap_purge(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + int32_t i,n; + // while still in orderbook, wait + //return; + portable_mutex_lock(&myinfo->DEX_swapmutex); + n = myinfo->numswaps; + for (i=0; iswaps[i] == swap ) + { + myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; + myinfo->swaps[myinfo->numswaps] = 0; + basilisk_swap_finished(myinfo,swap); + break; + } + portable_mutex_unlock(&myinfo->DEX_swapmutex); +} + +int32_t basilisk_verify_otherstatebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.otherstatebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); + return(retval); + } else return(-1); +} + +int32_t basilisk_verify_statebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.statebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); + if ( statebits != swap->I.statebits ) + { + printf("statebits.%x != %x\n",statebits,swap->I.statebits); + return(-1); + } + } + return(retval); +} + +int32_t basilisk_verify_choosei(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t otherchoosei=-1,i,len = 0; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 ) + { + len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei); + if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE ) + { + //printf("otherchoosei.%d\n",otherchoosei); + swap->I.otherchoosei = otherchoosei; + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + swap->I.pubA0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubA1.bytes[i] = data[len++]; + char str[65]; printf("GOT pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); + } + else + { + for (i=0; i<32; i++) + swap->I.pubB0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubB1.bytes[i] = data[len++]; + } + return(0); + } + } + printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2)); + return(-1); +} + +int32_t basilisk_swapdata_deck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,datalen = 0; + for (i=0; ideck)/sizeof(swap->deck[0][0]); i++) + datalen += iguana_rwnum(1,&data[datalen],sizeof(swap->deck[i>>1][i&1]),&swap->deck[i>>1][i&1]); + return(datalen); +} + +int32_t basilisk_verify_otherdeck(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t i,len = 0; struct basilisk_swap *swap = ptr; + for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) + len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); + return(0); +} + +int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t i,j,wrongfirstbyte=0,errs=0,len = 0; bits256 otherpriv,pubi; uint8_t secret160[20],otherpubkey[33]; uint64_t txid; struct basilisk_swap *swap = ptr; + //printf("verify privkeys choosei.%d otherchoosei.%d datalen.%d vs %d\n",swap->choosei,swap->otherchoosei,datalen,(int32_t)sizeof(swap->privkeys)+20+32); + memset(otherpriv.bytes,0,sizeof(otherpriv)); + if ( swap->I.cutverified == 0 && swap->I.otherchoosei >= 0 && datalen == sizeof(swap->privkeys)+20+2*32 ) + { + for (i=errs=0; iprivkeys)/sizeof(*swap->privkeys); i++) + { + for (j=0; j<32; j++) + otherpriv.bytes[j] = data[len++]; + if ( i != swap->I.choosei ) + { + pubi = bitcoin_pubkey33(myinfo->ctx,otherpubkey,otherpriv); + revcalc_rmd160_sha256(secret160,otherpriv);//.bytes,sizeof(otherpriv)); + memcpy(&txid,secret160,sizeof(txid)); + errs += basilisk_verify_pubpair(&wrongfirstbyte,swap,i,otherpubkey[0],pubi,txid); + } + } + if ( errs == 0 && wrongfirstbyte == 0 ) + { + swap->I.cutverified = 1, printf("CUT VERIFIED\n"); + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + swap->I.pubAm.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretAm[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretAm256[i] = data[len++]; + basilisk_bobscripts_set(myinfo,swap,1,1); + } + else + { + for (i=0; i<32; i++) + swap->I.pubBn.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretBn[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretBn256[i] = data[len++]; + //basilisk_bobscripts_set(myinfo,swap,0); + } + } else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs); + } + //printf("privkeys errs.%d wrongfirstbyte.%d\n",errs,wrongfirstbyte); + return(errs); +} + +uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) +{ + uint8_t sendbuf[32768]; int32_t sendlen; + if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 ) + { + if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + { + char str[65],str2[65]; + rawtx->I.actualtxid = basilisk_swap_broadcast(rawtx->name,myinfo,swap,rawtx->coin,rawtx->txbytes,rawtx->I.datalen); + if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) + { + printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + rawtx->I.actualtxid = rawtx->I.signedtxid; + } + if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) + { + sendlen = 0; + sendbuf[sendlen++] = rawtx->I.datalen & 0xff; + sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; + sendbuf[sendlen++] = rawtx->I.redeemlen; + memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + { + memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); + sendlen += rawtx->I.redeemlen; + } + basilisk_dontforget_update(myinfo,swap,rawtx); + //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); + if ( suppress_swapsend == 0 ) + return(basilisk_swapsend(myinfo,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); + else + { + printf("suppress swapsend %x\n",msgbits); + return(0); + } + } + } + return(nextbits); + } else if ( swap->I.iambob == 0 ) + printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); + return(0); +} + +void basilisk_sendpubkeys(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t datalen; + datalen = basilisk_swapdata_deck(myinfo,swap,data,maxlen); + printf("send deck.%d\n",datalen); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x02,data,datalen,0x01,swap->I.crcs_mypub); +} + +int32_t basilisk_checkdeck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + if ( (swap->I.statebits & 0x02) == 0 ) + { + //printf("check for other deck\n"); + if ( basilisk_swapget(myinfo,swap,0x02,data,maxlen,basilisk_verify_otherdeck) == 0 ) + swap->I.statebits |= 0x02; + else return(-1); + } + return(0); +} + +void basilisk_sendstate(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t datalen=0; + datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); + basilisk_swapsend(myinfo,swap,0x80000000,data,datalen,0,0); +} + +void basilisk_sendchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,datalen; char str[65]; + datalen = iguana_rwnum(1,data,sizeof(swap->I.choosei),&swap->I.choosei); + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubB0.bytes[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubB1.bytes[i]; + printf("SEND pubB0/1 %s\n",bits256_str(str,swap->I.pubB0)); + } + else + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubA0.bytes[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubA1.bytes[i]; + printf("SEND pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); + } + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x08,data,datalen,0x04,swap->I.crcs_mychoosei); +} + +void basilisk_waitchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + uint8_t pubkey33[33]; char str[65],str2[65]; + //printf("check otherchoosei\n"); + if ( basilisk_swapget(myinfo,swap,0x08,data,maxlen,basilisk_verify_choosei) == 0 ) + { + if ( swap->I.iambob != 0 ) + { + if ( bits256_nonz(swap->I.privBn) == 0 ) + { + swap->I.privBn = swap->privkeys[swap->I.otherchoosei]; + memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); + revcalc_rmd160_sha256(swap->I.secretBn,swap->I.privBn);//.bytes,sizeof(swap->privBn)); + vcalc_sha256(0,swap->I.secretBn256,swap->I.privBn.bytes,sizeof(swap->I.privBn)); + swap->I.pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privBn); + printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); + basilisk_bobscripts_set(myinfo,swap,1,1); + } + } + else + { + if ( bits256_nonz(swap->I.privAm) == 0 ) + { + swap->I.privAm = swap->privkeys[swap->I.otherchoosei]; + memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); + revcalc_rmd160_sha256(swap->I.secretAm,swap->I.privAm);//.bytes,sizeof(swap->privAm)); + vcalc_sha256(0,swap->I.secretAm256,swap->I.privAm.bytes,sizeof(swap->I.privAm)); + swap->I.pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privAm); + char str[65],str2[65]; printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + //basilisk_bobscripts_set(myinfo,swap,0); + } + } + swap->I.statebits |= 0x08; + } +} + +void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,j,datalen; + datalen = 0; + for (i=0; iprivkeys)/sizeof(*swap->privkeys); i++) + { + for (j=0; j<32; j++) + data[datalen++] = (i == swap->I.otherchoosei) ? 0 : swap->privkeys[i].bytes[j]; + } + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubBn.bytes[i]; + for (i=0; i<20; i++) + data[datalen++] = swap->I.secretBn[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.secretBn256[i]; + } + else + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubAm.bytes[i]; + for (i=0; i<20; i++) + data[datalen++] = swap->I.secretAm[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.secretAm256[i]; + } + //printf("send privkeys.%d\n",datalen); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x20,data,datalen,0x10,swap->I.crcs_myprivs); +} + +int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; + if ( swap->I.iambob != 0 ) + swap->I.statebits |= 0x80; + while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee + { + if ( basilisk_swapget(myinfo,swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) + { + // verify and submit otherfee + swap->I.statebits |= 0x80; + basilisk_sendstate(myinfo,swap,data,maxlen); + } + } + else if ( swap->I.iambob == 0 ) + swap->I.statebits |= 0x80; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) + break; + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + if ( (swap->I.otherstatebits & 0x80) == 0 ) + basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + } + basilisk_swap_saveupdate(myinfo,swap); + while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee + { + basilisk_swap_saveupdate(myinfo,swap); + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + //if ( (rand() % 30) == 0 ) + printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 ) + { + //printf("BOB\n"); + if ( (swap->I.statebits & 0x100) == 0 ) + { + printf("send bobdeposit\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); + } + // [BLOCKING: altfound] make sure altpayment is confirmed and send payment + else if ( (swap->I.statebits & 0x1000) == 0 ) + { + printf("check alicepayment\n"); + if ( basilisk_swapget(myinfo,swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) + { + swap->I.statebits |= 0x1000; + printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + } + } + else if ( (swap->I.statebits & 0x2000) == 0 ) + { + if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->alicepayment) >= swap->I.aliceconfirms ) + { + swap->I.statebits |= 0x2000; + printf("alicepayment confirmed\n"); + } + } + else if ( (swap->I.statebits & 0x4000) == 0 ) + { + basilisk_bobscripts_set(myinfo,swap,0,1); + printf("send bobpayment\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); + } + // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain + else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) + { + if ( basilisk_swapget(myinfo,swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(myinfo,swap) == 0 ) // divulges privAm + { + //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); + basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) + printf("Bob error spending alice payment\n"); + else + { + tradebot_swap_balancingtrade(myinfo,swap,1); + printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + swap->I.statebits |= 0x40000; + if ( basilisk_numconfirms(myinfo,swap,&swap->bobspend) >= swap->I.aliceconfirms ) + { + printf("bobspend confirmed\n"); + swap->I.statebits |= 0x80000; + printf("Bob confirming spend of Alice's payment\n"); + sleep(DEX_SLEEP); + } + retval = 1; + } + } + } + if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) + { + // submit reclaim of payment + printf("bob reclaims bobpayment\n"); + swap->I.statebits |= (0x40000 | 0x80000); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) + printf("Bob error reclaiming own payment after alice timed out\n"); + else + { + printf("Bob reclaimed own payment\n"); + while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? + { + if ( basilisk_numconfirms(myinfo,swap,&swap->bobreclaim) >= 1 ) + { + printf("bobreclaim confirmed\n"); + swap->I.statebits |= 0x100000; + printf("Bob confirms reclain of payment\n"); + break; + } + } + retval = 1; + } + } + } + else + { + //printf("ALICE\n"); + // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment + if ( (swap->I.statebits & 0x200) == 0 ) + { + printf("checkfor deposit\n"); + if ( basilisk_swapget(myinfo,swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) + { + // verify deposit and submit, set confirmed height + printf("got bobdeposit\n"); + swap->I.statebits |= 0x200; + } else printf("no valid deposit\n"); + } + else if ( (swap->I.statebits & 0x400) == 0 ) + { + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) + { + printf("bobdeposit confirmed\n"); + swap->I.statebits |= 0x400; + } + } + else if ( (swap->I.statebits & 0x800) == 0 ) + { + printf("send alicepayment\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); + } + // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim + else if ( (swap->I.statebits & 0x8000) == 0 ) + { + if ( basilisk_swapget(myinfo,swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) + { + printf("got bobpayment\n"); + tradebot_swap_balancingtrade(myinfo,swap,0); + // verify payment and submit, set confirmed height + swap->I.statebits |= 0x8000; + } + } + else if ( (swap->I.statebits & 0x10000) == 0 ) + { + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) + { + printf("bobpayment confirmed\n"); + swap->I.statebits |= 0x10000; + } + } + else if ( (swap->I.statebits & 0x20000) == 0 ) + { + printf("alicespend bobpayment\n"); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(myinfo,swap,&swap->alicespend) > 0) ) + { + swap->I.statebits |= 0x20000; + } + } + else if ( (swap->I.statebits & 0x40000) == 0 ) + { + int32_t numconfs; + if ( (numconfs= basilisk_numconfirms(myinfo,swap,&swap->alicespend)) >= swap->I.bobconfirms ) + { + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privAm.bytes[j]; + printf("send privAm %x\n",swap->I.statebits); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); + printf("Alice confirms spend of Bob's payment\n"); + retval = 1; + } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); + } + if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) + { + printf("Alice claims deposit\n"); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) + printf("Alice couldnt claim deposit\n"); + else + { + printf("Alice claimed deposit\n"); + retval = 1; + } + } + else if ( swap->aborted != 0 || basilisk_privBn_extract(myinfo,swap,data,maxlen) == 0 ) + { + printf("Alice reclaims her payment\n"); + swap->I.statebits |= 0x40000000; + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) + printf("Alice error sending alicereclaim\n"); + else + { + printf("Alice reclaimed her payment\n"); + retval = 1; + } + } + } + if ( (rand() % 30) == 0 ) + printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + } + return(retval); +} + +int32_t swapcompleted(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + if ( swap->I.iambob != 0 ) + return(swap->I.bobspent); + else return(swap->I.alicespent); +} + +cJSON *swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + cJSON *retjson = cJSON_CreateObject(); + return(retjson); +} + +void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp) +{ + char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; + if ( swap->connected == 1 ) + return; + if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + swap->pushsock = pushsock; + swap->subsock = subsock; + } + if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) + { + printf("error getting nn_sockets\n"); + return; + } + sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); + if ( swap->connected == 0 && (retstr= _dex_kvsearch(myinfo,"KV",keystr)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (datastr= jstr(retjson,"value")) != 0 ) + { + datalen = (int32_t)strlen(datastr) >> 1; + decode_hex((uint8_t *)databuf,datalen,datastr); + if ( (addrjson= cJSON_Parse(databuf)) != 0 ) + { + pushaddr = jstr(addrjson,"push"); + subaddr = jstr(addrjson,"sub"); + if ( pushaddr != 0 && subaddr != 0 ) + { + printf("KV decoded (%s and %s) %d %d\n",pushaddr,subaddr,swap->pushsock,swap->subsock); + if ( nn_connect(swap->pushsock,pushaddr) >= 0 && nn_connect(swap->subsock,subaddr) >= 0 ) + swap->connected = 1; + } + free_json(addrjson); + } + } + free_json(retjson); + } + printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); + free(retstr); + } + printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); + if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) + { + if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) + { + printf("psock returns.(%s)\n",retstr); + // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + pushaddr = jstr(retjson,"pushaddr"); + subaddr = jstr(retjson,"subaddr"); + if ( pushaddr != 0 && subaddr != 0 ) + { + if ( nn_connect(pushsock,pushaddr) >= 0 ) + { + printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); + if ( nn_connect(subsock,subaddr) >= 0 ) + { + swap->connected = 1; + init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); + datalen = (int32_t)strlen((char *)data) + 1; + printf("datalen.%d (%s)\n",datalen,(char *)data); + init_hexbytes_noT(databuf,data,datalen); + printf("%s -> %s\n",keystr,databuf); + if ( (retstr2= _dex_kvupdate(myinfo,"KV",keystr,databuf,1)) != 0 ) + { + printf("KVupdate.(%s)\n",retstr2); + free(retstr2); + } + } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); + } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); + } + else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); + free_json(retjson); + } else printf("Error parsing psock.(%s)\n",retstr); + free(retstr); + } else printf("error issuing _dex_psock\n"); + } +} + +int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,retval = -1; + printf("alicetxs\n"); + for (i=0; i<3; i++) + { + if ( swap->alicepayment.I.datalen == 0 ) + basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) + { + printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); + sleep(20); + } + else + { + retval = 0; + for (i=0; ialicepayment.I.datalen; i++) + printf("%02x",swap->alicepayment.txbytes[i]); + printf(" ALICE PAYMENT created\n"); + iguana_unspents_mark(myinfo,swap->alicecoin,swap->alicepayment.vins); + basilisk_txlog(myinfo,swap,&swap->alicepayment,-1); + break; + } + } + if ( swap->myfee.I.datalen == 0 ) + { + printf("generate fee\n"); + if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + { + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); + basilisk_txlog(myinfo,swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + } + else + { + printf("error creating myfee\n"); + return(-2); + } + } + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) + return(0); + return(-1); +} + +void basilisk_swaploop(void *_swap) +{ + uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; + myinfo = swap->myinfoptr; + fprintf(stderr,"start swap\n"); + maxlen = 1024*1024 + sizeof(*swap); + data = malloc(maxlen); + expiration = (uint32_t)time(NULL) + 300; + myinfo->DEXactive = expiration; + channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) + { + dex_channelsend(myinfo,swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + if ( swap->connected > 0 ) + { + printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_sendpubkeys(myinfo,swap,data,maxlen); // send pubkeys + if ( basilisk_checkdeck(myinfo,swap,data,maxlen) == 0) // check for other deck 0x02 + basilisk_sendchoosei(myinfo,swap,data,maxlen); + basilisk_waitchoosei(myinfo,swap,data,maxlen); // wait for choosei 0x08 + if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + } + if ( swap->connected == 0 ) + { + printf("couldnt establish connection\n"); + retval = -1; + } + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_sendchoosei(myinfo,swap,data,maxlen); + basilisk_sendmostprivs(myinfo,swap,data,maxlen); + if ( basilisk_swapget(myinfo,swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) + { + swap->I.statebits |= 0x20; + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + if ( time(NULL) > expiration ) + break; + } + myinfo->DEXactive = swap->I.expiration; + if ( time(NULL) >= expiration ) + { + retval = -1; + myinfo->DEXactive = 0; + } + if ( swap->aborted != 0 ) + { + printf("swap aborted before tx sent\n"); + retval = -1; + } + printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); + iters = 0; + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + //printf("sendstate.%x\n",swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + //printf("swapget\n"); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + //printf("after swapget\n"); + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) + { + printf("bobscripts set\n"); + if ( basilisk_bobscripts_set(myinfo,swap,1,1) < 0 ) + { + sleep(DEX_SLEEP); + printf("bobscripts set error\n"); + continue; + } + } + if ( swap->I.iambob == 0 ) + { + /*for (i=0; i<20; i++) + printf("%02x",swap->secretAm[i]); + printf(" <- secretAm\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretAm256[i]); + printf(" <- secretAm256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubAm.bytes[i]); + printf(" <- pubAm\n"); + for (i=0; i<20; i++) + printf("%02x",swap->secretBn[i]); + printf(" <- secretBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretBn256[i]); + printf(" <- secretBn256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubBn.bytes[i]); + printf(" <- pubBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA0.bytes[i]); + printf(" <- pubA0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA1.bytes[i]); + printf(" <- pubA1\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB0.bytes[i]); + printf(" <- pubB0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB1.bytes[i]); + printf(" <- pubB1\n");*/ + if ( (retval= basilisk_alicetxs(myinfo,swap,data,maxlen)) != 0 ) + { + printf("basilisk_alicetxs error\n"); + break; + } + } + } + if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) + { + printf("couldnt send fee\n"); + retval = -8; + } + if ( retval == 0 ) + { + if ( swap->I.iambob == 0 && (swap->myfee.I.datalen == 0 || swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.datalen == 0) ) + { + printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); + retval = -7; + } + else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 + { + printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); + retval = -7; + } + } + while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) + { + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_swap_saveupdate(myinfo,swap); + if ( time(NULL) > swap->I.expiration ) + break; + } + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + { + printf("BOB waiting for confirm state.%x\n",swap->I.statebits); + sleep(60); // wait for confirm/propagation of msig + printf("BOB reclaims refund\n"); + basilisk_bobdeposit_refund(myinfo,swap,0); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn + { + printf("Bob submit error getting refund of deposit\n"); + } + else + { + // maybe wait for bobrefund to be confirmed + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privBn.bytes[j]; + basilisk_swapsend(myinfo,swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); + } + basilisk_swap_saveupdate(myinfo,swap); + } + if ( retval != 0 ) + basilisk_swap_sendabort(myinfo,swap); + printf("end of atomic swap\n"); + if ( swapcompleted(myinfo,swap) > 0 ) // only if swap completed + { + if ( swap->I.iambob != 0 ) + tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + else tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); + } + printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); + basilisk_swap_purge(myinfo,swap); + free(data); +} + +cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + cJSON *item = cJSON_CreateObject(); + jaddnum(item,"requestid",swap->I.req.requestid); + jaddnum(item,"quoteid",swap->I.req.quoteid); + jaddnum(item,"state",swap->I.statebits); + jaddnum(item,"otherstate",swap->I.otherstatebits); + jadd(item,"request",basilisk_requestjson(&swap->I.req)); + return(item); +} + +struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +{ + int32_t i,m,n,iter; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; + // statebits 1 -> client, 0 -> LP + if ( myinfo->numswaps > 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have SRC coin.%s or not native and already swap pending\n",rp->src); + return(0); + } + if ( (coin= iguana_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have DEST coin.%s or not native and already swap pending\n",rp->dest); + return(0); + } + } + portable_mutex_lock(&myinfo->DEX_swapmutex); + for (i=0; inumswaps; i++) + if ( myinfo->swaps[i]->I.req.requestid == rp->requestid ) + { + printf("basilisk_thread_start error trying to start requestid.%u which is already started\n",rp->requestid); + break; + } + if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) ) + { + swap = calloc(1,sizeof(*swap)); + swap->subsock = swap->pushsock = -1; + vcalc_sha256(0,swap->I.orderhash.bytes,(uint8_t *)rp,sizeof(*rp)); + swap->I.req = *rp; + swap->myinfoptr = myinfo; + printf("basilisk_thread_start request.%u statebits.%d (%s/%s) reinit.%d\n",rp->requestid,statebits,rp->src,rp->dest,reinit); + bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + pubkey25519 = curve25519(privkey,curve25519_basepoint9()); + swap->persistent_pubkey = pubkey25519; + swap->persistent_privkey = privkey; + memcpy(swap->persistent_pubkey33,pubkey33,33); + m = n = 0; + if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) + { + for (iter=0; iter<16; iter++) + { + basilisk_psockinit(myinfo,swap,statebits == 0); + sleep(3); + if ( swap->connected > 0 ) + break; + sleep(10); + /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); + basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); + if ( swap->connected > 0 ) + break; + printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock);*/ + } + if ( reinit != 0 ) + { + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) + { + + } + myinfo->swaps[myinfo->numswaps++] = swap; + } + else + { + starttime = (uint32_t)time(NULL); + printf("statebits.%x m.%d n.%d\n",statebits,m,n); + while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+7*BASILISK_MSGDURATION ) + { + uint32_t msgid; uint8_t data[1024]; int32_t datalen; + m = n = 0; + sleep(DEX_SLEEP); + printf("waiting for offer to be accepted\n"); + channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + datalen = basilisk_rwDEXquote(1,data,rp); + msgid = (uint32_t)time(NULL); + printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) last.%u r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,myinfo->lastdexrequestid,rp->requestid,rp->quoteid); + dex_channelsend(myinfo,rp->desthash,rp->srchash,channel,msgid,data,datalen); + if ( (retarray= basilisk_channelget(myinfo,rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) + { + if ( is_cJSON_Array(retarray) != 0 && (n= cJSON_GetArraySize(retarray)) > 0 ) + { + for (i=0; i 0 ) + { + item = jitem(msgobj,0); + if ( jobj(item,"data") != 0 && jobj(item,"key") != 0 ) + m++; + else printf("(%s)\n",jprint(item,0)); + } //else printf("msgobj.%p m.%d n.%d\n",msgobj,m,n); + } + } + } else printf("no retarray\n"); + } + printf("LAUNCH check.%d m.%d\n",statebits,m); + if ( statebits != 0 || m > 0 )//n/2 ) + { + //for (i=0; iI.req); i++) + // fprintf(stderr,"%02x",((uint8_t *)&swap->I.req)[i]); + fprintf(stderr," M.%d N.%d launch.%d %d %p reinit.%d\n",m,n,myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps)),&swap->I.req,reinit); + if ( (swap->fp= basilisk_swap_save(myinfo,swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) + { + } + if ( reinit == 0 ) + { + if ( myinfo->swapsfp == 0 ) + { + char fname[512]; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) == 0 ) + myinfo->swapsfp = fopen(fname,"wb+"); + else fseek(myinfo->swapsfp,0,SEEK_END); + printf("LIST fp.%p\n",myinfo->swapsfp); + } + if ( myinfo->swapsfp != 0 ) + { + fwrite(&rp->requestid,1,sizeof(rp->requestid),myinfo->swapsfp); + fwrite(&rp->quoteid,1,sizeof(rp->quoteid),myinfo->swapsfp); + fflush(myinfo->swapsfp); + } + } + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) + { + + } + myinfo->swaps[myinfo->numswaps++] = swap; + } + else + { + if ( statebits != 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) != 0 ) + { + + } + } + printf("%u/%u offer wasnt accepted statebits.%d m.%d n.%d pending %.8f\n",rp->requestid,rp->quoteid,statebits,m,n,pending); + } + } + } + } + portable_mutex_unlock(&myinfo->DEX_swapmutex); + return(swap); +} + +/////////////// remember functions + diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 7ea3b1f63..04f20f410 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -26,6 +26,7 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" +#include "LP_prices.c" #if defined(__APPLE__) || defined(WIN32) || defined(USE_STATIC_NANOMSG) #include "../../crypto777/nanosrc/nn.h" @@ -716,6 +717,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } } } + LP_priceupdate(base,rel,theoretical,avebid,aveask,highbid,lowask,PAXPRICES); } if ( strcmp(exchange,"bittrex") == 0 ) { @@ -790,7 +792,13 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } } -#include "LP_unspents.c" +#include "LP_nativeDEX.c" + +void LP_main(void *ptr) +{ + double profitmargin = *(double *)ptr; + LPinit(7779,7780,7781,profitmargin); +} int main(int argc, const char * argv[]) { @@ -802,7 +810,11 @@ int main(int argc, const char * argv[]) minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); profitmargin = jdouble(retjson,"profitmargin"); - LPinit(7779,7780,7781,profitmargin); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)&profitmargin) != 0 ) + { + printf("error launching LP_main %f\n",profitmargin); + exit(-1); + } getchar(); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index 8403f91d7..61f7f60b0 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -638,9 +638,10 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } height = kmd_height(coin); loadheight = coin->kmd_height+1; - if ( strcmp(coin->symbol,"LTC") == 0 ) - lag = 3; - else lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); + //if ( strcmp(coin->symbol,"LTC") == 0 ) + // lag = 3; + //else + lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); while ( loadheight < height-lag ) { flag = 0; @@ -749,7 +750,7 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } free_json(blockjson); } - if ( flag != 0 || num > 500 ) + if ( flag != 0 || num > 100 ) break; coin->kmd_height = loadheight++; } @@ -771,7 +772,7 @@ void kmd_bitcoinscan() { //if ( strcmp("KMD",coin->symbol) == 0 ) _kmd_bitcoinscan(coin); - usleep(250000); + sleep(1); } } }