You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

491 lines
23 KiB

/******************************************************************************
* Copyright © 2014-2016 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. *
* *
******************************************************************************/
#include "../exchanges/bitcoin.h"
/*
bitcoin_pubkey33(pubkey,myinfo->persistent_priv);
bitcoin_address(coinaddr,other->chain->pubtype,pubkey,sizeof(pubkey));
bitcoin_addr2rmd160(&addrtype,secret160,coinaddr);
scriptlen = bitcoin_cltvscript(coinbtc->chain->p2shtype,p2sh_coinaddr,p2sh_rmd160,script,0,senderaddr,otheraddr,secret160,locktime);
if ( jobj(argjson,"p2sh") != 0 )
{
if ( strcmp(jstr(argjson,"p2sh"),p2sh_coinaddr) != 0 )
{
printf("mismatched p2sh.(%s) vs (%s)\n",jstr(argjson,"p2sh"),p2sh_coinaddr);
return(clonestr("{\"error\":\"instantdex_BTCswap base or rel mismatch\"}"));
}
}
*/
#define INSTANTDEX_DONATION 2000
// https://github.com/TierNolan/bips/blob/bip4x/bip-atom.mediawiki
uint64_t instantdex_relsatoshis(uint64_t price,uint64_t volume)
{
if ( volume > price )
return(price * dstr(volume));
else return(dstr(price) * volume);
}
bits256 instantdex_sharedpub256(bits256 *sharedprivp,uint8_t pubkey[33],bits256 privkey,bits256 hash,int32_t n)
{
bits256 shared,iters; int32_t i;
iters = shared = curve25519_shared(privkey,hash);
for (i=0; i<n; i++)
iters = curve25519(iters,curve25519(iters,curve25519_basepoint9()));
vcalc_sha256cat(sharedprivp->bytes,shared.bytes,sizeof(shared),iters.bytes,sizeof(iters));
return(bitcoin_pubkey33(pubkey,*sharedprivp));
}
int32_t instantdex_pubkeyargs(bits256 *sharedprivs,cJSON *argjson,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte)
{
char buf[3]; int32_t i,n; bits256 tmp; uint8_t pubkey[33];
sprintf(buf,"%c0",'A' - 0x02 + firstbyte);
for (i=n=0; i<numpubs*100&&n<numpubs; i++)
{
tmp = instantdex_sharedpub256(&sharedprivs[n],pubkey,privkey,hash,i+1);
if ( pubkey[0] != firstbyte )
continue;
buf[1] = '0' + n++;
jaddbits256(argjson,buf,tmp);
}
return(n);
}
int32_t bitcoin_2of2spendscript(int32_t *paymentlenp,uint8_t *paymentscript,uint8_t *msigscript,bits256 pub0,bits256 pub1)
{
struct vin_info V; uint8_t p2sh_rmd160[20]; int32_t p2shlen;
memset(&V,0,sizeof(V));
V.M = V.N = 2;
memcpy(V.signers[0].pubkey+1,pub0.bytes,sizeof(pub0)), V.signers[0].pubkey[0] = 0x02;
memcpy(V.signers[1].pubkey+1,pub1.bytes,sizeof(pub1)), V.signers[1].pubkey[0] = 0x03;
p2shlen = bitcoin_MofNspendscript(p2sh_rmd160,msigscript,0,&V);
*paymentlenp = bitcoin_p2shspend(paymentscript,0,p2sh_rmd160);
return(p2shlen);
}
struct bitcoin_unspent *instantdex_bestfit(struct iguana_info *coin,struct bitcoin_unspent *unspents,int32_t numunspents,uint64_t value,int32_t mode)
{
int32_t i; uint64_t above,below,gap,atx_value; struct bitcoin_unspent *vin,*abovevin,*belowvin;
abovevin = belowvin = 0;
for (above=below=i=0; i<numunspents; i++)
{
vin = &unspents[i];
atx_value = vin->value;
//printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(value));
if ( atx_value == value )
return(vin);
else if ( atx_value > value )
{
gap = (atx_value - value);
if ( above == 0 || gap < above )
{
above = gap;
abovevin = vin;
}
}
else if ( mode == 0 )
{
gap = (value - atx_value);
if ( below == 0 || gap < below )
{
below = gap;
belowvin = vin;
}
}
}
if ( (vin= (abovevin != 0) ? abovevin : belowvin) == 0 && mode == 1 )
vin = unspents;
return(vin);
}
struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *numunspentsp)
{
struct bitcoin_unspent *ups = calloc(1,sizeof(*ups)); //uint8_t addrtype;
// struct bitcoin_unspent { bits256 txid,privkey; uint64_t value; int32_t vout; };
*numunspentsp = 0;
return(ups);
}
struct bitcoin_spend *instantdex_spendset(struct supernet_info *myinfo,struct iguana_info *coin,uint64_t satoshis,uint64_t donation)
{
int32_t i,mode,numunspents,maxinputs = 1024; int64_t remains; struct bitcoin_unspent *ptr,*up;
struct bitcoin_unspent *ups; struct bitcoin_spend *spend;
if ( (ups= iguana_unspentsget(myinfo,coin,&numunspents)) == 0 )
return(0);
spend = calloc(1,sizeof(*spend) + sizeof(*spend->inputs) * maxinputs);
spend->satoshis = satoshis;
spend->txfee = coin->chain->txfee;
if ( strcmp(coin->symbol,"BTC") == 0 )
remains = spend->txfee + spend->satoshis + donation;
ptr = spend->inputs;
for (i=0; i<maxinputs; i++,ptr++)
{
for (mode=1; mode>=0; mode--)
if ( (up= instantdex_bestfit(coin,ups,numunspents,remains,mode)) != 0 )
break;
if ( up != 0 )
{
spend->input_satoshis += up->value;
spend->inputs[spend->numinputs++] = *up;
if ( spend->input_satoshis >= satoshis )
{
spend->netamount = (spend->input_satoshis - spend->txfee - donation);
spend->change = (spend->input_satoshis - spend->netamount);
printf("numinputs %d sum %.8f vs satoshis %.8f change %.8f -> txfee %.8f\n",spend->numinputs,dstr(spend->input_satoshis),dstr(satoshis),dstr(spend->change),dstr(spend->input_satoshis - spend->change - spend->netamount));
break;
}
remains -= up->value;
} else break;
}
if ( spend->input_satoshis >= (satoshis + spend->txfee) )
{
spend = realloc(spend,sizeof(*spend) + sizeof(*spend->inputs) * spend->numinputs);
return(spend);
}
else
{
free(spend);
return(0);
}
}
/*
Name: Bob.Bail.In
Input value: B + 2*fb + change
Input source: (From Bob's coins, multiple inputs are allowed)
vout0 value: B, ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL
vout1 value: fb, ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUALVERIFY pub-A1 OP_CHECKSIG
vout2 value: change, ScriptPubKey 2: <= 100 bytes
P2SH Redeem: OP_2 pub-A1 pub-B1 OP_2 OP_CHECKMULTISIG
Name: Alice.Bail.In
vins: A + 2*fa + change, Input source: (From Alice's altcoins, multiple inputs are allowed)
vout0 value: A, ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL
vout1 value: fa, ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUAL
vout2 value: change, ScriptPubKey 2: <= 100 bytes
*/
char *instantdex_bailintx(struct iguana_info *coin,bits256 *txidp,struct bitcoin_spend *spend,bits256 A0,bits256 B0,uint8_t x[20],int32_t isbob)
{
uint64_t change; char *rawtxstr,*signedtx; struct vin_info *V; bits256 txid,signedtxid;
int32_t p2shlen,i; cJSON *txobj; int32_t scriptv0len,scriptv1len,scriptv2len;
uint8_t p2shscript[256],scriptv0[128],scriptv1[128],changescript[128],pubkey[35];
p2shlen = bitcoin_2of2spendscript(&scriptv0len,scriptv0,p2shscript,A0,B0);
txobj = bitcoin_createtx(coin,0);
bitcoin_addoutput(coin,txobj,scriptv0,scriptv0len,spend->satoshis);
if ( isbob != 0 )
{
scriptv1len = bitcoin_revealsecret160(scriptv1,0,x);
scriptv1len = bitcoin_pubkeyspend(scriptv1,scriptv1len,pubkey);
} else scriptv1len = bitcoin_p2shspend(scriptv1,0,x);
bitcoin_addoutput(coin,txobj,scriptv1,scriptv1len,spend->txfee);
if ( (scriptv2len= bitcoin_changescript(coin,changescript,0,&change,spend->changeaddr,spend->input_satoshis,spend->satoshis,spend->txfee)) > 0 )
bitcoin_addoutput(coin,txobj,changescript,scriptv2len,change);
for (i=0; i<spend->numinputs; i++)
bitcoin_addinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,0xffffffff);
rawtxstr = bitcoin_json2hex(coin,&txid,txobj);
char str[65]; printf("%s_bailin.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,txid),rawtxstr);
V = calloc(spend->numinputs,sizeof(*V));
for (i=0; i<spend->numinputs; i++)
V[i].signers[0].privkey = spend->inputs[i].privkey;
bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,V);
free(rawtxstr), free(V);
if ( signedtx != 0 )
printf("signed %s_bailin.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,signedtxid),signedtx);
else printf("error generating signedtx\n");
free_json(txobj);
*txidp = txid;
return(signedtx);
}
cJSON *instantdex_bailinspend(struct iguana_info *coin,bits256 privkey,uint64_t amount)
{
bits256 hash; int32_t n; cJSON *txobj;
int32_t scriptv0len; uint8_t p2shscript[256],rmd160[20],scriptv0[128],pubkey[35];
bitcoin_pubkey33(pubkey,privkey);
n = bitcoin_pubkeyspend(p2shscript,0,pubkey);
vcalc_sha256(0,hash.bytes,p2shscript,n);
calc_rmd160(0,rmd160,hash.bytes,sizeof(hash.bytes));
scriptv0len = bitcoin_p2shspend(scriptv0,0,rmd160);
txobj = bitcoin_createtx(coin,0);
bitcoin_addoutput(coin,txobj,scriptv0,scriptv0len,amount);
return(txobj);
}
/*
Name: Bob.Payout
vin0: A, Input source: Alice.Bail.In:0
vin1: fa, Input source: Alice.Bail.In:1
vout0: A, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-B2 OP_CHECKSIG
Name: Alice.Payout
vin0: B, Input source: Bob.Bail.In:0
vin1: fb, Input source: Bob.Bail.In:1
vout0: B, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-A2 OP_CHECKSIG
*/
char *instantdex_bailinsign(struct iguana_info *coin,bits256 bailinpriv,char *sigstr,int32_t *siglenp,bits256 *txidp,struct vin_info *V,cJSON *txobj,int32_t isbob)
{
char *rawtxstr,*signedtx;
rawtxstr = bitcoin_json2hex(coin,txidp,txobj);
char str[65]; printf("%s_payout.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,*txidp),rawtxstr);
V->signers[isbob].privkey = bailinpriv;
bitcoin_verifytx(coin,txidp,&signedtx,rawtxstr,V);
*siglenp = V->signers[isbob].siglen;
init_hexbytes_noT(sigstr,V->signers[isbob].sig,*siglenp);
free(rawtxstr);
if ( signedtx != 0 )
printf("signed %s_payout.%s (%s) sig.%s\n",isbob!=0?"bob":"alice",bits256_str(str,*txidp),signedtx,sigstr);
else printf("error generating signedtx\n");
free_json(txobj);
return(signedtx);
}
char *instantdex_payouttx(struct iguana_info *coin,char *sigstr,int32_t *siglenp,bits256 *txidp,bits256 *sharedprivs,bits256 bailintxid,int64_t amount,int64_t txfee,int32_t isbob,char *othersigstr)
{
struct vin_info V; cJSON *txobj;
txobj = instantdex_bailinspend(coin,sharedprivs[1],amount);
bitcoin_addinput(coin,txobj,bailintxid,0,0xffffffff);
bitcoin_addinput(coin,txobj,bailintxid,1,0xffffffff);
memset(&V,0,sizeof(V));
if ( othersigstr != 0 )
{
printf("OTHERSIG.(%s)\n",othersigstr);
V.signers[isbob ^ 1].siglen = (int32_t)strlen(othersigstr) >> 1;
decode_hex(V.signers[isbob ^ 1].sig,V.signers[isbob ^ 1].siglen,othersigstr);
}
return(instantdex_bailinsign(coin,sharedprivs[0],sigstr,siglenp,txidp,&V,txobj,isbob));
}
/*
Name: Alice.Refund
vin0: A, Input source: Alice.Bail.In:0
vout0: A - fa, ScriptPubKey: OP_HASH160 Hash160(P2SH) OP_EQUAL; P2SH Redeem: pub-A3 OP_CHECKSIG
Locktime: current block height + ((T/2)/(altcoin block rate))
Name: Bob.Refund
vin0: B, Input source: Bob.Bail.In:0
vout0: B - fb, ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL; P2SH Redeem: pub-B3 OP_CHECKSIG
Locktime: (current block height) + (T / 10 minutes)
*/
char *instantdex_refundtx(struct iguana_info *coin,bits256 *txidp,bits256 bailinpriv,bits256 priv2,bits256 bailintxid,int64_t amount,int64_t txfee,int32_t isbob)
{
char sigstr[256]; int32_t siglen; struct vin_info V; cJSON *txobj;
txobj = instantdex_bailinspend(coin,priv2,amount - txfee);
bitcoin_addinput(coin,txobj,bailintxid,0,0xffffffff);
return(instantdex_bailinsign(coin,bailinpriv,sigstr,&siglen,txidp,&V,txobj,isbob));
}
int32_t instantdex_calcx20(char hexstr[41],uint8_t *p2shscript,uint8_t firstbyte,bits256 pub)
{
uint8_t pubkey[33],rmd160[20]; int32_t n; bits256 hash;
memcpy(pubkey+1,pub.bytes,sizeof(pub)), pubkey[0] = firstbyte;
n = bitcoin_pubkeyspend(p2shscript,0,pubkey);
vcalc_sha256(0,hash.bytes,p2shscript,n);
calc_rmd160(0,rmd160,hash.bytes,sizeof(hash.bytes));
init_hexbytes_noT(hexstr,rmd160,sizeof(rmd160));
return(n);
}
char *instantdex_btcoffer(struct supernet_info *myinfo,struct exchange_info *exchange,char *othercoin,double othervolume,double maxprice) // Bob sending to network (Alice)
{
char *str,coinaddr[64],xstr[41]; uint8_t xscript[64]; struct iguana_info *other; int32_t isbob = 1;
struct instantdex_accept checkA,A; cJSON *newjson; bits256 hash,pub3,sharedprivs[4];
if ( othercoin == 0 || (other= iguana_coinfind(othercoin)) == 0 )
return(clonestr("{\"error\":\"invalid othercoin\"}"));
hash = instantdex_acceptset(&A,othercoin,"BTC",INSTANTDEX_OFFERDURATION,1,-1,maxprice,othervolume,myinfo->myaddr.nxt64bits);
newjson = instantdex_acceptsendjson(&A);
if ( instantdex_acceptextract(&checkA,newjson) < 0 )
{
int32_t i;
for (i=0; i<sizeof(A); i++)
printf("%02x ",((uint8_t *)&A)[i]);
printf("instantdex_btcoffer checkA error\n");
}
if ( instantdex_pubkeyargs(sharedprivs,newjson,4,myinfo->persistent_priv,hash,0x02+isbob) != 4 )
return(clonestr("{\"error\":\"highly unlikely run of 02 pubkeys\"}"));
pub3 = jbits256(newjson,"B3");
jdelete(newjson,"B3");
instantdex_calcx20(xstr,xscript,0x02+isbob,pub3);
jaddstr(newjson,"x",xstr);
if ( coinaddr[0] != 0 )
jaddstr(newjson,othercoin,coinaddr);
if ( maxprice > 0. )
{
if ( (str= InstantDEX_maxaccept(myinfo,0,newjson,0,othercoin,"BTC",maxprice,othervolume)) != 0 )
free(str);
}
return(instantdex_sendcmd(myinfo,newjson,"BTCoffer",myinfo->ipaddr,INSTANTDEX_HOPS));
}
void instantdex_pendingnotice(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap,struct instantdex_accept *A)
{
printf("need to start monitoring thread\n");
ap->pendingvolume64 -= A->A.basevolume64;
}
cJSON *instantdex_newjson(struct supernet_info *myinfo,bits256 *A0p,bits256 *B0p,bits256 *sharedprivs,uint8_t secret160[20],int32_t isbob,cJSON *argjson,bits256 hash,struct instantdex_accept *A)
{
cJSON *newjson; char *xstr;
newjson = instantdex_acceptsendjson(A);
if ( instantdex_pubkeyargs(sharedprivs,newjson,3+isbob,myinfo->persistent_priv,hash,0x02+isbob) != 3 )
return(0);
if ( isbob == 0 )
*A0p = jbits256(newjson,"A0");
else *A0p = jbits256(argjson,"A0");
*B0p = jbits256(argjson,"B0");
if ( (xstr= jstr(argjson,"x")) != 0 )
{
decode_hex(secret160,20,xstr);
jaddstr(newjson,"x",xstr);
}
return(newjson);
}
char *instantdex_bailinrefund(struct supernet_info *myinfo,struct iguana_info *coin,struct exchange_info *exchange,struct instantdex_accept *A,char *nextcmd,uint8_t secret160[20],cJSON *newjson,int32_t isbob,bits256 A0,bits256 B0,bits256 *sharedprivs)
{
struct bitcoin_spend *spend; char *bailintx,*refundtx,field[64]; bits256 bailintxid,refundtxid;
if ( bits256_nonz(A0) > 0 && bits256_nonz(B0) > 0 )
{
if ( (spend= instantdex_spendset(myinfo,coin,A->A.basevolume64,INSTANTDEX_DONATION)) != 0 )
{
bailintx = instantdex_bailintx(coin,&bailintxid,spend,A0,B0,secret160,0);
refundtx = instantdex_refundtx(coin,&refundtxid,sharedprivs[0],sharedprivs[2],bailintxid,A->A.basevolume64,coin->chain->txfee,isbob);
if ( A->statusjson == 0 )
A->statusjson = cJSON_CreateObject();
sprintf(field,"bailin%c",'A'+isbob), jaddstr(A->statusjson,field,bailintx), free(bailintx);
sprintf(field,"refund%c",'A'+isbob), jaddstr(A->statusjson,field,refundtx), free(refundtx);
sprintf(field,"bailintx%c",'A'+isbob), jaddbits256(A->statusjson,field,bailintxid);
sprintf(field,"bailintxid%c",'A'+isbob), jaddbits256(newjson,field,bailintxid);
free(spend);
return(instantdex_sendcmd(myinfo,newjson,nextcmd,myinfo->ipaddr,INSTANTDEX_HOPS));
} else return(clonestr("{\"error\":\"couldnt create bailintx\"}"));
} else return(clonestr("{\"error\":\"dont have pubkey0 pair\"}"));
}
cJSON *instantdex_payout(struct supernet_info *myinfo,struct iguana_info *coin,struct exchange_info *exchange,struct instantdex_accept *A,uint8_t secret160[20],int32_t isbob,bits256 *A0p,bits256 *B0p,bits256 *sharedprivs,bits256 hash,uint64_t satoshis[2],cJSON *argjson)
{
cJSON *newjson; char field[32],payoutsigstr[256],*signedpayout; int32_t payoutsiglen; bits256 payouttxid,bailintxid;
if ( (newjson= instantdex_newjson(myinfo,A0p,B0p,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
return(0);
sprintf(field,"bailintxid%c",'A' + (isbob^1)), bailintxid = jbits256(argjson,field);
sprintf(field,"payoutsig%c",'A' + (isbob^1));
if ( (signedpayout= instantdex_payouttx(coin,payoutsigstr,&payoutsiglen,&payouttxid,sharedprivs,bailintxid,satoshis[isbob],coin->chain->txfee,isbob,jstr(argjson,field))) != 0 )
{
sprintf(field,"payoutsig%c",'A'+isbob), jaddstr(newjson,field,payoutsigstr);
if ( A->statusjson == 0 )
A->statusjson = cJSON_CreateObject();
sprintf(field,"payout%c",'A'+isbob), jaddstr(A->statusjson,field,signedpayout);
free(signedpayout);
}
return(newjson);
}
char *instantdex_advance(struct supernet_info *myinfo,bits256 *sharedprivs,int32_t isbob,cJSON *argjson,bits256 hash,char *addfield,char *nextstate,struct instantdex_accept *A)
{
cJSON *newjson; bits256 A0,B0; uint8_t secret160[20];
if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
if ( A->statusjson != 0 && jstr(A->statusjson,addfield) != 0 )
{
jaddstr(newjson,addfield,jstr(A->statusjson,addfield));
if ( nextstate != 0 )
return(instantdex_sendcmd(myinfo,newjson,nextstate,myinfo->ipaddr,INSTANTDEX_HOPS));
else return(clonestr("{\"result\":\"instantdex_BTCswap advance complete, wait or refund\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap advance cant find statusjson\"}"));
}
char *instantdex_BTCswap(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,char *cmdstr,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *data,int32_t datalen) // receiving side
{
uint8_t secret160[20]; bits256 hash,A0,B0,sharedprivs[4]; uint64_t satoshis[2]; cJSON *newjson;
struct instantdex_accept *ap; char *retstr=0,*str;
int32_t locktime,isbob=0,offerdir = 0; struct iguana_info *coinbtc,*other;
if ( exchange == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap null exchange ptr\"}"));
offerdir = instantdex_bidaskdir(A);
if ( (other= iguana_coinfind(A->A.base)) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap cant find btc or other coin info\"}"));
locktime = (uint32_t)(A->A.expiration + INSTANTDEX_OFFERDURATION);
if ( strcmp(A->A.rel,"BTC") != 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer non BTC rel\"}"));
vcalc_sha256(0,hash.bytes,(void *)&A->A,sizeof(ap->A));
if ( hash.txid != A->orderid )
return(clonestr("{\"error\":\"txid mismatches orderid\"}"));
satoshis[0] = A->A.basevolume64;
satoshis[1] = instantdex_relsatoshis(A->A.price64,A->A.basevolume64);
printf("got offer.(%s) offerside.%d offerdir.%d\n",jprint(argjson,0),A->A.myside,A->A.acceptdir);
if ( strcmp(cmdstr,"offer") == 0 ) // sender is Bob, receiver is network (Alice)
{
if ( A->A.expiration < (time(NULL) + INSTANTDEX_DURATION) )
return(clonestr("{\"error\":\"instantdex_BTCswap offer too close to expiration\"}"));
if ( (ap= instantdex_acceptable(exchange,A,myinfo->myaddr.nxt64bits)) != 0 )
{
isbob = 0;
if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
else
{
// should add to orderbook if not accepted
instantdex_pendingnotice(myinfo,exchange,ap,A);
return(instantdex_bailinrefund(myinfo,other,exchange,A,"proposal",secret160,newjson,isbob,A0,B0,sharedprivs));
}
}
else
{
printf("no matching trade.(%s)\n",jprint(argjson,0));
if ( (str= InstantDEX_minaccept(myinfo,0,argjson,0,A->A.base,"BTC",dstr(A->A.price64),dstr(A->A.basevolume64))) != 0 )
free(str);
}
}
else if ( strcmp(cmdstr,"proposal") == 0 ) // sender is Alice, receiver is Bob
{
isbob = 1;
newjson = instantdex_payout(myinfo,coinbtc,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson);
return(instantdex_bailinrefund(myinfo,coinbtc,exchange,A,"BTCaccept",secret160,newjson,isbob,A0,B0,sharedprivs));
}
else if ( strcmp(cmdstr,"accept") == 0 ) // sender is Bob, receiver is Alice
{
isbob = 0;
newjson = instantdex_payout(myinfo,other,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson);
return(instantdex_sendcmd(myinfo,newjson,"BTCconfirm",myinfo->ipaddr,INSTANTDEX_HOPS));
}
else if ( strcmp(cmdstr,"confirm") == 0 ) // sender is Alice, receiver is Bob
{
isbob = 1;
newjson = instantdex_payout(myinfo,coinbtc,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson);
return(instantdex_sendcmd(myinfo,newjson,"BTCbroadcast",myinfo->ipaddr,INSTANTDEX_HOPS));
}
else if ( strcmp(cmdstr,"broadcast") == 0 ) // sender is Bob, receiver is Alice
{
isbob = 0;
return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"bailintxA","BTCcommit",A));
}
else if ( strcmp(cmdstr,"commit") == 0 ) // sender is Alice, receiver is Bob
{
isbob = 1;
// go into refund state, ie watch for payouts to complete or get refund
return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"payoutB","BTCcomplete",A));
}
else if ( strcmp(cmdstr,"complete") == 0 ) // sender is Bob, receiver is Alice
{
isbob = 0;
// go into refund state, ie watch for payouts to complete or get refund
return(instantdex_advance(myinfo,sharedprivs,isbob,argjson,hash,"payoutA",0,A));
}
else retstr = clonestr("{\"error\":\"BTC swap got unrecognized command\"}");
if ( retstr == 0 )
retstr = clonestr("{\"error\":\"BTC swap null retstr\"}");
return(retstr);
}