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.

1433 lines
69 KiB

9 years ago
/******************************************************************************
* 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. *
* *
******************************************************************************/
9 years ago
#include "../exchanges/bitcoin.h"
9 years ago
/* https://bitcointalk.org/index.php?topic=1340621.msg13828271#msg13828271
9 years ago
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
*/
9 years ago
9 years ago
/*
9 years ago
both fees are standard payments: OP_DUP OP_HASH160 FEE_RMD160 OP_EQUALVERIFY OP_CHECKSIG
Alice altpayment: OP_2 <alice_pubM> <bob_pubN> OP_2 OP_CHECKMULTISIG
Bob deposit:
OP_IF
<now + INSTANTDEX_LOCKTIME*2> OP_CLTV OP_DROP <alice_pubA0> OP_CHECKSIG
OP_ELSE
OP_HASH160 <hash(bob_privN)> OP_EQUALVERIFY <bob_pubB0> OP_CHECKSIG
OP_ENDIF
Bob paytx:
OP_IF
<now + INSTANTDEX_LOCKTIME> OP_CLTV OP_DROP <bob_pubB1> OP_CHECKSIG
OP_ELSE
OP_HASH160 <hash(alice_privM)> OP_EQUALVERIFY <alice_pubA0> OP_CHECKSIG
OP_ENDIF
Naming convention are pubAi are alice's pubkeys (seems only pubA0 and not pubA1)
pubBi are Bob's pubkeys
9 years ago
9 years ago
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
*/
int32_t instantdex_bobscript(uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct bitcoin_swapinfo *swap,int32_t depositflag)
9 years ago
{
9 years ago
uint8_t pubkeyA[33],pubkeyB[33],*secret160; bits256 cltvpub,destpub; int32_t i;
9 years ago
*locktimep = swap->locktime;
if ( depositflag != 0 )
{
*locktimep += INSTANTDEX_LOCKTIME;
cltvpub = swap->pubA0;
destpub = swap->pubB0;
secret160 = swap->secretBn;
pubkeyA[0] = 0x02;
pubkeyB[0] = 0x03;
}
else
{
cltvpub = swap->pubB1;
destpub = swap->pubA0;
secret160 = swap->secretAm;
pubkeyA[0] = 0x03;
pubkeyB[0] = 0x02;
}
9 years ago
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);
9 years ago
memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub));
memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub));
9 years ago
script[n++] = SCRIPT_OP_IF;
9 years ago
n = bitcoin_checklocktimeverify(script,n,*locktimep);
9 years ago
n = bitcoin_pubkeyspend(script,n,pubkeyA);
9 years ago
script[n++] = SCRIPT_OP_ELSE;
if ( secretstartp != 0 )
*secretstartp = n + 2;
9 years ago
n = bitcoin_revealsecret160(script,n,secret160);
n = bitcoin_pubkeyspend(script,n,pubkeyB);
9 years ago
script[n++] = SCRIPT_OP_ENDIF;
return(n);
}
int32_t instantdex_alicescript(uint8_t *script,int32_t n,char *msigaddr,uint8_t altps2h,bits256 pubAm,bits256 pubBn)
{
uint8_t p2sh160[20]; struct vin_info V;
memset(&V,0,sizeof(V));
memcpy(&V.signers[0].pubkey[1],pubAm.bytes,sizeof(pubAm)), V.signers[0].pubkey[0] = 0x02;
memcpy(&V.signers[1].pubkey[1],pubBn.bytes,sizeof(pubBn)), V.signers[1].pubkey[0] = 0x03;
V.M = V.N = 2;
n = bitcoin_MofNspendscript(p2sh160,script,n,&V);
bitcoin_address(msigaddr,altps2h,p2sh160,sizeof(p2sh160));
return(n);
}
9 years ago
int32_t instantdex_outputinsurance(char *coinaddr,uint8_t addrtype,uint8_t *script,int64_t insurance,uint64_t r,uint64_t dest)
9 years ago
{
9 years ago
uint8_t rmd160[20]; int32_t n = 0;
decode_hex(rmd160,sizeof(rmd160),(dest % 10) == 9 ? TIERNOLAN_RMD160 : INSTANTDEX_RMD160);
9 years ago
//script[n++] = sizeof(r);
//n += iguana_rwnum(1,&script[n],sizeof(r),&r);
//script[n++] = SCRIPT_OP_DROP;
9 years ago
bitcoin_address(coinaddr,addrtype,rmd160,20);
9 years ago
n = bitcoin_standardspend(script,n,rmd160);
return(n);
}
void disp_tx(struct supernet_info *myinfo,struct iguana_info *coin,char *str,char *txbytes)
{
cJSON *txobj; bits256 txid;
txobj = bitcoin_hex2json(coin,&txid,0,txbytes);
9 years ago
printf("disp_tx (%s) -> %s.(%s)\n",txbytes,str,jprint(txobj,1));
}
9 years ago
struct bitcoin_statetx *instantdex_getstatetx(struct bitcoin_swapinfo *swap,char *txname)
{
//char *txnames[] = { "fee", "dep", "alt", "acl", "bre", "bcl", "bfr", "are", "adp" };
if ( strcmp(txname,"fee") == 0 )
return(swap->otherfee);
else if ( strcmp(txname,"dep") == 0 )
return(swap->deposit);
else if ( strcmp(txname,"alt") == 0 )
return(swap->altpayment);
else if ( strcmp(txname,"acl") == 0 )
return(swap->payment);
else if ( strcmp(txname,"bre") == 0 )
return(swap->deposit);
else if ( strcmp(txname,"bcl") == 0 )
return(swap->altpayment);
else if ( strcmp(txname,"bfr") == 0 )
return(swap->myfee);
else if ( strcmp(txname,"are") == 0 )
return(swap->altpayment);
else if ( strcmp(txname,"adp") == 0 )
return(swap->deposit);
printf("unrecognized txname.(%s)\n",txname);
return(0);
}
9 years ago
void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence)
{
int32_t i,j,plen; uint8_t *pubkeyptrs[16];
9 years ago
for (i=0; i<spend->numinputs; i++)
{
spend->inputs[i].sequence = sequence;
for (j=0; j<16; j++)
{
if ( (plen= bitcoin_pubkeylen(spend->inputs[i].pubkeys[j])) < 0 )
break;
pubkeyptrs[j] = spend->inputs[i].pubkeys[j];
}
bitcoin_txinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,spend->inputs[i].sequence,spend->inputs[i].spendscript,spend->inputs[i].spendlen,spend->inputs[i].p2shscript,spend->inputs[i].p2shlen,j>0?pubkeyptrs:0,j);
9 years ago
}
}
9 years ago
struct bitcoin_statetx *instantdex_signtx(char *str,struct supernet_info *myinfo,struct iguana_info *coin,uint32_t locktime,char *scriptstr,int64_t satoshis,int64_t txfee,int32_t minconf,int32_t myside)
9 years ago
{
9 years ago
struct iguana_waddress *waddr; struct iguana_waccount *wacct; struct bitcoin_statetx *tx=0; uint8_t pubkey33[33]; char coinaddr[64],wifstr[64]; char *rawtx,*signedtx,*retstr; bits256 signedtxid; uint32_t rawtxtag; int32_t flag,completed; cJSON *valsobj,*vins,*retjson=0,*privkey,*argjson,*addresses;
9 years ago
if ( (waddr= iguana_getaccountaddress(myinfo,coin,0,0,coin->changeaddr,"change")) == 0 )
return(0);
privkey = cJSON_CreateArray();
addresses = cJSON_CreateArray();
9 years ago
if ( coin->changeaddr[0] == 0 )
9 years ago
bitcoin_address(coin->changeaddr,coin->chain->pubtype,waddr->rmd160,20);
9 years ago
bitcoin_pubkey33(myinfo->ctx,pubkey33,myinfo->persistent_priv);
bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33);
9 years ago
//printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr);
9 years ago
if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,coinaddr)) != 0 )
{
bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype);
jaddistr(privkey,waddr->wifstr);
}
9 years ago
jaddistr(addresses,coinaddr);
9 years ago
valsobj = cJSON_CreateObject();
jaddstr(valsobj,"coin",coin->symbol);
jadd64bits(valsobj,"amount",satoshis);
jadd64bits(valsobj,"txfee",txfee);
jaddnum(valsobj,"minconf",minconf);
rawtxtag = (uint32_t)rand();
jaddnum(valsobj,"rawtxtag",rawtxtag);
jaddnum(valsobj,"locktime",locktime);
argjson = cJSON_CreateObject();
jaddnum(argjson,"timeout",15000);
if ( (retstr= iguana_rawtx(myinfo,coin,argjson,0,coin->changeaddr,addresses,valsobj,scriptstr)) != 0 )
9 years ago
{
9 years ago
//printf("feetx got.(%s)\n",retstr);
9 years ago
flag = 0;
if ( (retjson= cJSON_Parse(retstr)) != 0 )
9 years ago
{
9 years ago
if ( (rawtx= jstr(retjson,"result")) != 0 && (vins= jobj(retjson,"vins")) != 0 )
flag = 1;
}
if ( flag == 0 )
{
vins = 0;
if ( (rawtx= iguana_pollrawtx(&myinfo->rawtxQ,&vins,rawtxtag,OS_milliseconds() + 10000)) != 0 )
{
if ( vins != 0 )
flag = 2;
}
}
9 years ago
if ( flag != 0 && vins != 0 )
9 years ago
{
9 years ago
//printf("vins.(%s)\n",jprint(vins,0));
if ( (signedtx= iguana_signrawtx(myinfo,coin,&signedtxid,&completed,vins,rawtx,privkey)) != 0 )
9 years ago
{
iguana_unspentslock(myinfo,coin,vins);
9 years ago
tx = calloc(1,sizeof(*tx) + strlen(signedtx) + 1);
9 years ago
strcpy(tx->txbytes,signedtx);
tx->txid = signedtxid;
9 years ago
printf("%s %s.%s\n",myside != 0 ? "BOB" : "ALICE",str,signedtx);
9 years ago
free(signedtx);
}
}
if ( retjson != 0 )
free_json(retjson);
if ( flag == 2 )
{
free_json(vins);
9 years ago
printf("Free rawtx\n");
9 years ago
free(rawtx);
}
free(retstr);
9 years ago
} else printf("error creating %s feetx\n",myside != 0 ? "BOB" : "ALICE");
free_json(addresses);
9 years ago
free_json(argjson);
9 years ago
return(tx);
}
9 years ago
struct bitcoin_statetx *instantdex_feetx(struct supernet_info *myinfo,struct instantdex_accept *A,struct bitcoin_swapinfo *swap,struct iguana_info *coin)
9 years ago
{
9 years ago
int32_t n; uint8_t paymentscript[128]; char scriptstr[512],coinaddr[64]; struct bitcoin_statetx *ptr = 0; uint64_t r;
9 years ago
r = swap->mine.orderid;
9 years ago
n = instantdex_outputinsurance(coinaddr,coin->chain->pubtype,paymentscript,swap->insurance + swap->coinbtc->chain->txfee,r,r * (strcmp("BTC",coin->symbol) == 0));
9 years ago
init_hexbytes_noT(scriptstr,paymentscript,n);
9 years ago
printf("instantdex_feetx %s %.8f (%s)\n",coin->symbol,dstr(swap->insurance + swap->coinbtc->chain->txfee),scriptstr);
if ( (ptr= instantdex_signtx("feetx",myinfo,coin,0,scriptstr,swap->insurance + swap->coinbtc->chain->txfee,coin->txfee,0,A->offer.myside)) != 0 )
9 years ago
strcpy(ptr->destaddr,coinaddr);
9 years ago
return(ptr);
9 years ago
}
9 years ago
int32_t instantdex_feetxverify(struct supernet_info *myinfo,struct iguana_info *coin,struct bitcoin_swapinfo *swap,cJSON *argjson)
9 years ago
{
9 years ago
cJSON *txobj; bits256 txid; uint32_t n; int32_t i,retval = -1; int64_t insurance; uint64_t r;
9 years ago
struct iguana_msgtx msgtx; uint8_t script[512]; char coinaddr[64];
9 years ago
if ( swap->otherfee != 0 )
9 years ago
{
9 years ago
if ( (txobj= bitcoin_hex2json(coin,&txid,&msgtx,swap->otherfee->txbytes)) != 0 )
9 years ago
{
9 years ago
r = swap->other.orderid;
9 years ago
if ( strcmp(coin->symbol,"BTC") == 0 )
9 years ago
insurance = swap->insurance + swap->coinbtc->chain->txfee;
else insurance = swap->altinsurance + swap->altcoin->chain->txfee;
9 years ago
n = instantdex_outputinsurance(coinaddr,coin->chain->pubtype,script,insurance,r,r * (strcmp("BTC",coin->symbol) == 0));
9 years ago
if ( n == msgtx.vouts[0].pk_scriptlen )
{
if ( memcmp(script,msgtx.vouts[0].pk_script,n) == 0 )
{
9 years ago
printf("feetx script verified.(%s)\n",swap->otherfee->txbytes);
9 years ago
retval = 0;
9 years ago
}
else
{
for (i=0; i<n; i++)
9 years ago
printf("%02x",script[i]);
9 years ago
printf(" fee script\n");
9 years ago
for (i=0; i<n; i++)
9 years ago
printf("%02x",msgtx.vouts[0].pk_script[i]);
9 years ago
printf(" feetx mismatched\n");
9 years ago
printf("FEETX.(%s)\n",jprint(txobj,0));
9 years ago
}
9 years ago
} else printf("pk_scriptlen %d mismatch %d\n",msgtx.vouts[0].pk_scriptlen,n);
9 years ago
free_json(txobj);
9 years ago
} else printf("error converting (%s) txobj\n",swap->otherfee->txbytes);
9 years ago
} else printf("no feetx to verify\n");
9 years ago
return(retval);
}
9 years ago
struct bitcoin_statetx *instantdex_bobtx(struct supernet_info *myinfo,struct bitcoin_swapinfo *swap,struct iguana_info *coin,int64_t amount,int32_t depositflag)
9 years ago
{
9 years ago
int32_t n,secretstart; struct bitcoin_statetx *ptr = 0; uint8_t script[1024]; uint32_t locktime; int64_t satoshis; char scriptstr[512];
9 years ago
if ( coin == 0 )
return(0);
9 years ago
satoshis = amount + depositflag*swap->insurance*100 + swap->coinbtc->chain->txfee;
n = instantdex_bobscript(script,0,&locktime,&secretstart,swap,depositflag);
if ( n < 0 )
9 years ago
{
9 years ago
printf("instantdex_bobtx couldnt generate bobscript deposit.%d\n",depositflag);
9 years ago
return(0);
}
9 years ago
printf("locktime.%u amount %.8f satoshis %.8f\n",locktime,dstr(amount),dstr(satoshis));
9 years ago
init_hexbytes_noT(scriptstr,script,n);
9 years ago
if ( (ptr= instantdex_signtx(depositflag != 0 ? "deposit" : "payment",myinfo,coin,locktime,scriptstr,satoshis,coin->txfee,swap->mine.minconfirms,swap->mine.offer.myside)) != 0 )
9 years ago
{
bitcoin_address(ptr->destaddr,coin->chain->p2shtype,script,n);
printf("BOBTX.%d (%s) -> %s\n",depositflag,ptr->txbytes,ptr->destaddr);
}
9 years ago
return(ptr);
9 years ago
}
9 years ago
9 years ago
int32_t instantdex_paymentverify(struct supernet_info *myinfo,struct iguana_info *coin,struct bitcoin_swapinfo *swap,cJSON *argjson,int32_t depositflag)
9 years ago
{
cJSON *txobj; bits256 txid; uint32_t n,locktime; int32_t i,secretstart,retval = -1; uint64_t x;
9 years ago
struct iguana_msgtx msgtx; uint8_t script[512]; int64_t amount;
if ( coin != 0 && swap->deposit != 0 )
9 years ago
{
9 years ago
amount = swap->BTCsatoshis + depositflag*swap->insurance*100 + swap->coinbtc->chain->txfee;
9 years ago
if ( (n= instantdex_bobscript(script,0,&locktime,&secretstart,swap,depositflag)) <= 0 )
return(retval);
9 years ago
if ( (txobj= bitcoin_hex2json(coin,&txid,&msgtx,swap->deposit->txbytes)) != 0 )
9 years ago
{
9 years ago
memcpy(&script[secretstart],&msgtx.vouts[0].pk_script[secretstart],20);
9 years ago
printf("locktime.%u amount %.8f satoshis %.8f\n",locktime,dstr(amount),dstr(amount));
9 years ago
if ( msgtx.lock_time == locktime && msgtx.vouts[0].value == amount && n == msgtx.vouts[0].pk_scriptlen )
{
if ( memcmp(script,msgtx.vouts[0].pk_script,n) == 0 )
{
iguana_rwnum(0,&script[secretstart],sizeof(x),&x);
9 years ago
printf("deposit script verified x.%llx vs otherdeck %llx\n",(long long)x,(long long)swap->otherdeck[swap->choosei][0]);
if ( x == swap->otherdeck[swap->choosei][0] )
9 years ago
retval = 0;
9 years ago
else printf("deposit script verified but secret mismatch x.%llx vs otherdeck %llx\n",(long long)x,(long long)swap->otherdeck[swap->choosei][0]);
9 years ago
}
else
{
for (i=0; i<n; i++)
printf("%02x ",script[i]);
printf("script\n");
for (i=0; i<n; i++)
printf("%02x ",msgtx.vouts[0].pk_script[i]);
printf("deposit\n");
}
}
free_json(txobj);
}
}
9 years ago
return(retval);
9 years ago
}
9 years ago
int32_t instantdex_altpaymentverify(struct supernet_info *myinfo,struct iguana_info *coin,struct bitcoin_swapinfo *swap,cJSON *argjson)
9 years ago
{
cJSON *txobj; bits256 txid; uint32_t n; int32_t i,retval = -1;
struct iguana_msgtx msgtx; uint8_t script[512]; char *altmsigaddr,msigaddr[64];
if ( jstr(argjson,"altpayment") != 0 && (altmsigaddr= jstr(argjson,"altmsigaddr")) != 0 )
{
9 years ago
if ( swap->altpayment != 0 && (txobj= bitcoin_hex2json(coin,&txid,&msgtx,swap->altpayment->txbytes)) != 0 )
9 years ago
{
n = instantdex_alicescript(script,0,msigaddr,coin->chain->p2shtype,swap->pubAm,swap->pubBn);
if ( strcmp(msigaddr,altmsigaddr) == 0 && n == msgtx.vouts[0].pk_scriptlen )
{
if ( memcmp(script,msgtx.vouts[0].pk_script,n) == 0 )
{
9 years ago
printf("altpayment script verified\n");
retval = 0;
9 years ago
}
else
{
for (i=0; i<n; i++)
printf("%02x ",script[i]);
printf("altscript\n");
for (i=0; i<n; i++)
printf("%02x ",msgtx.vouts[0].pk_script[i]);
printf("altpayment\n");
}
}
free_json(txobj);
}
}
9 years ago
return(retval);
9 years ago
}
9 years ago
struct bitcoin_statetx *instantdex_alicetx(struct supernet_info *myinfo,struct iguana_info *altcoin,char *msigaddr,bits256 pubAm,bits256 pubBn,int64_t amount,struct bitcoin_swapinfo *swap)
9 years ago
{
9 years ago
int32_t n; uint8_t script[1024]; char scriptstr[2048]; struct bitcoin_statetx *ptr = 0;
if ( altcoin != 0 )
9 years ago
{
9 years ago
if ( bits256_nonz(pubAm) == 0 || bits256_nonz(pubBn) == 0 )
{
printf("instantdex_bobtx null pubAm.%llx or pubBn.%llx\n",(long long)pubAm.txid,(long long)pubBn.txid);
return(0);
}
9 years ago
n = instantdex_alicescript(script,0,msigaddr,altcoin->chain->p2shtype,pubAm,pubBn);
9 years ago
init_hexbytes_noT(scriptstr,script,n);
9 years ago
if ( (ptr= instantdex_signtx("altpayment",myinfo,altcoin,0,scriptstr,amount,altcoin->txfee,swap->mine.minconfirms,swap->mine.offer.myside)) != 0 )
9 years ago
{
strcpy(ptr->destaddr,msigaddr);
printf("ALICETX (%s) -> %s\n",ptr->txbytes,ptr->destaddr);
}
9 years ago
}
9 years ago
return(ptr);
9 years ago
}
9 years ago
cJSON *BTC_makeclaimfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
9 years ago
int32_t got_payment=1,bob_reclaimed=0;
9 years ago
*serdatap = 0, *serdatalenp = 0;
9 years ago
if ( instantdex_isbob(swap) == 0 )
{
// [BLOCKING: payfound] now Alice's turn to make sure payment is confrmed and send in claim or see bob's reclaim and reclaim
if ( got_payment != 0 )
{
swap->privAm = swap->privkeys[swap->otherchoosei];
// sign if/else payment
}
else if ( bob_reclaimed != 0 )
{
}
}
else
{
// [BLOCKING: privM] Bob waits for privM either from Alice or alt blockchain
if ( bits256_nonz(swap->privAm) != 0 )
{
// a multisig tx for altcoin
}
}
9 years ago
return(newjson);
9 years ago
}
9 years ago
bits256 instantdex_derivekeypair(struct supernet_info *myinfo,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash)
9 years ago
{
9 years ago
bits256 sharedsecret;
sharedsecret = curve25519_shared(privkey,orderhash);
vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret));
9 years ago
return(bitcoin_pubkey33(myinfo->ctx,pubkey,*newprivp));
9 years ago
}
9 years ago
int32_t instantdex_pubkeyargs(struct supernet_info *myinfo,struct bitcoin_swapinfo *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte)
9 years ago
{
9 years ago
char buf[3]; int32_t i,n,m,len=0; bits256 pubi; uint64_t txid; uint8_t secret160[20],pubkey[33];
9 years ago
sprintf(buf,"%c0",'A' - 0x02 + firstbyte);
9 years ago
if ( numpubs > 2 )
9 years ago
{
if ( swap->numpubs+2 >= numpubs )
return(numpubs);
9 years ago
printf(">>>>>> start generating %s\n",buf);
9 years ago
}
9 years ago
for (i=n=m=0; i<numpubs*100 && n<numpubs; i++)
9 years ago
{
9 years ago
pubi = instantdex_derivekeypair(myinfo,&swap->privkeys[n],pubkey,privkey,hash);
9 years ago
privkey = swap->privkeys[n];
9 years ago
//printf("i.%d n.%d numpubs.%d %02x vs %02x\n",i,n,numpubs,pubkey[0],firstbyte);
9 years ago
if ( pubkey[0] != firstbyte )
continue;
9 years ago
if ( n < 2 )
9 years ago
{
9 years ago
if ( bits256_nonz(swap->mypubs[n]) == 0 )
memcpy(swap->mypubs[n].bytes,pubkey+1,sizeof(bits256));
9 years ago
}
9 years ago
if ( swap->numpubs < INSTANTDEX_DECKSIZE )
9 years ago
{
9 years ago
calc_rmd160_sha256(secret160,swap->privkeys[n].bytes,sizeof(swap->privkeys[n]));
9 years ago
memcpy(&txid,secret160,sizeof(txid));
9 years ago
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++;
9 years ago
if ( m > swap->numpubs )
swap->numpubs = m;
9 years ago
}
n++;
}
9 years ago
if ( n > 2 || m > 2 )
printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->numpubs);
9 years ago
return(n);
}
9 years ago
char *instantdex_choosei(struct bitcoin_swapinfo *swap,cJSON *newjson,cJSON *argjson,uint8_t *serdata,int32_t datalen)
9 years ago
{
9 years ago
int32_t i,j,max,len = 0; uint64_t x;
if ( swap->choosei < 0 && serdata != 0 && datalen == sizeof(swap->deck) )
9 years ago
{
9 years ago
max = (int32_t)(sizeof(swap->otherdeck) / sizeof(*swap->otherdeck));
9 years ago
for (i=0; i<max; i++)
for (j=0; j<2; j++)
9 years ago
len += iguana_rwnum(1,(uint8_t *)&swap->otherdeck[i][j],sizeof(x),&serdata[len]);
9 years ago
OS_randombytes((uint8_t *)&swap->choosei,sizeof(swap->choosei));
9 years ago
if ( swap->choosei < 0 )
swap->choosei = -swap->choosei;
9 years ago
swap->choosei %= max;
jaddnum(newjson,"mychoosei",swap->choosei);
9 years ago
printf("%llu/%llu %s send mychoosei.%d of max.%d deck.(%llx %llx)\n",(long long)swap->mine.orderid,(long long)swap->other.orderid,instantdex_isbob(swap)!=0?"BOB":"alice",swap->choosei,max,(long long)swap->otherdeck[0][0],(long long)swap->otherdeck[0][1]);
9 years ago
return(0);
9 years ago
}
else
{
9 years ago
printf("choosei.%d or null serdata.%p or invalid datalen.%d vs %d\n",swap->choosei,serdata,datalen,(int32_t)sizeof(swap->deck));
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer no cut\"}"));
}
9 years ago
}
9 years ago
void instantdex_privkeyextract(struct supernet_info *myinfo,struct bitcoin_swapinfo *swap,uint8_t *serdata,int32_t serdatalen)
9 years ago
{
9 years ago
int32_t i,wrongfirstbyte,errs,len = 0; bits256 hashpriv,otherpriv,pubi; uint8_t otherpubkey[33],pubkey[33]; char str[65];
9 years ago
if ( swap->cutverified == 0 && swap->choosei >= 0 && serdatalen == sizeof(swap->privkeys) )
{
for (i=wrongfirstbyte=errs=0; i<sizeof(swap->privkeys)/sizeof(*swap->privkeys); i++)
{
9 years ago
if ( i == 0 )
printf("raw recv.%s\n",*(bits256 *)serdata);
9 years ago
len += iguana_rwbignum(0,&serdata[len],sizeof(bits256),otherpriv.bytes);
9 years ago
if ( i == 0 )
printf("got instantdex_privkeyextract serdatalen.%d choosei.%d cutverified.%d priv0 %s\n",serdatalen,swap->choosei,swap->cutverified,bits256_str(str,otherpriv));
9 years ago
if ( i == swap->choosei )
{
if ( bits256_nonz(otherpriv) != 0 )
{
9 years ago
printf("got privkey in slot.%d my choosei??\n",i);
9 years ago
errs++;
}
9 years ago
if ( instantdex_isbob(swap) != 0 )
{
9 years ago
if ( otherpubkey[0] == 0x02 )
9 years ago
{
9 years ago
swap->pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey,swap->privBn);
9 years ago
} else printf("wrong first byte.%02x\n",otherpubkey[0]);
}
else
{
9 years ago
if ( otherpubkey[0] == 0x03 )
9 years ago
{
9 years ago
swap->pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey,swap->privAm);
9 years ago
} else printf("wrong first byte.%02x\n",otherpubkey[0]);
}
9 years ago
continue;
}
9 years ago
pubi = bitcoin_pubkey33(myinfo->ctx,otherpubkey,otherpriv);
9 years ago
vcalc_sha256(0,hashpriv.bytes,otherpriv.bytes,sizeof(otherpriv));
9 years ago
if ( otherpubkey[0] != (instantdex_isbob(swap) ^ 1) + 0x02 )
9 years ago
{
wrongfirstbyte++;
printf("wrongfirstbyte[%d] %02x\n",i,otherpubkey[0]);
}
9 years ago
else if ( swap->otherdeck[i][0] != hashpriv.txid )
9 years ago
{
9 years ago
printf("otherdeck[%d] priv mismatch %llx != %llx\n",i,(long long)swap->otherdeck[i][0],(long long)hashpriv.txid);
9 years ago
errs++;
}
9 years ago
else if ( swap->otherdeck[i][1] != pubi.txid )
9 years ago
{
9 years ago
printf("otherdeck[%d] priv mismatch %llx != %llx\n",i,(long long)swap->otherdeck[i][1],(long long)pubi.txid);
9 years ago
errs++;
}
}
if ( errs == 0 && wrongfirstbyte == 0 )
9 years ago
swap->cutverified = 1, printf("CUT VERIFIED\n");
9 years ago
else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs);
}
}
9 years ago
int32_t instantdex_swaptxupdate(struct iguana_info *coin,struct bitcoin_statetx **ptrp,cJSON *argjson,char *txname,char *txidfield)
9 years ago
{
9 years ago
char *str; int32_t retval = 0;
9 years ago
if ( (str= jstr(argjson,txname)) != 0 )
{
if ( *ptrp != 0 )
{
9 years ago
if ( strcmp((*ptrp)->txbytes,str) != 0 )
{
printf("got replacement %s?\n",txname);
free(*ptrp);
} else return(0);
9 years ago
} else printf("instantdex_swaptxupdate got (%s) %s\n",txname,str);
9 years ago
*ptrp = calloc(1,sizeof(**ptrp) + strlen(str) + 1);
strcpy((*ptrp)->txbytes,str);
(*ptrp)->txid = jbits256(argjson,txidfield);
9 years ago
iguana_txidmonitor(coin,(*ptrp)->txid);
9 years ago
if ( strcmp("feetx",txname) == 0 )
retval = INSTANTDEX_ORDERSTATE_HAVEOTHERFEE;
else if ( strcmp("deposit",txname) == 0 )
retval = INSTANTDEX_ORDERSTATE_HAVEDEPOSIT;
else if ( strcmp("payment",txname) == 0 )
retval = INSTANTDEX_ORDERSTATE_HAVEPAYMENT;
else if ( strcmp("altpayment",txname) == 0 )
retval = INSTANTDEX_ORDERSTATE_HAVEALTPAYMENT;
9 years ago
}
9 years ago
return(retval);
9 years ago
}
void instantdex_swapbits256update(bits256 *txidp,cJSON *argjson,char *fieldname)
{
bits256 txid; char str[65];
txid = jbits256(argjson,fieldname);
if ( bits256_nonz(txid) > 0 )
{
9 years ago
if ( 0 && bits256_nonz(*txidp) > 0 )
9 years ago
printf("swapbits256: %s sent again\n",bits256_str(str,*txidp));
*txidp = txid;
}
}
9 years ago
void instantdex_newjson(struct supernet_info *myinfo,struct bitcoin_swapinfo *swap,cJSON *newjson)
{
9 years ago
uint8_t pubkey[33],*secret160; int32_t deckflag; char secretstr[41],*field;
9 years ago
deckflag = (newjson != 0 && swap->otherchoosei < 0) ? 1 : 0;
9 years ago
if ( instantdex_pubkeyargs(myinfo,swap,2 + deckflag*INSTANTDEX_DECKSIZE,myinfo->persistent_priv,swap->myorderhash,0x02+instantdex_isbob(swap)) != 2 + deckflag*INSTANTDEX_DECKSIZE )
9 years ago
printf("ERROR: couldnt generate pubkeys deckflag.%d\n",deckflag);
9 years ago
jaddnum(newjson,"have",swap->havestate);
if ( swap->choosei >= 0 )
jaddnum(newjson,"mychoosei",swap->choosei);
9 years ago
if ( swap->otherchoosei >= 0 )
9 years ago
{
9 years ago
jaddnum(newjson,"otherchoosei",swap->otherchoosei);
9 years ago
if ( instantdex_isbob(swap) != 0 )
{
secret160 = swap->secretBn;
field = "secretBn";
}
else
{
secret160 = swap->secretAm;
field = "secretAm";
}
calc_rmd160_sha256(secret160,swap->privkeys[swap->otherchoosei].bytes,sizeof(swap->privkeys[swap->otherchoosei]));
init_hexbytes_noT(secretstr,secret160,20);
jaddstr(newjson,field,secretstr);
}
9 years ago
if ( swap->myfee != 0 && jobj(newjson,"feetx") == 0 && (swap->otherhavestate & INSTANTDEX_ORDERSTATE_HAVEOTHERFEE) == 0 )
{
jaddbits256(newjson,"feetxid",swap->myfee->txid);
jaddstr(newjson,"feetx",swap->myfee->txbytes);
printf("add feetx to newjson have.%x\n",swap->havestate);
}
if ( instantdex_isbob(swap) == 0 )
{
if ( (swap->otherhavestate & INSTANTDEX_ORDERSTATE_HAVEALTPAYMENT) == 0 && swap->altpayment != 0 && jobj(newjson,"altpayment") == 0 )
{
jaddbits256(newjson,"altpaymenttxid",swap->altpayment->txid);
jaddstr(newjson,"altpayment",swap->altpayment->txbytes);
9 years ago
jaddstr(newjson,"altmsigaddr",swap->altpayment->destaddr);
9 years ago
printf("add altpayment.(%s) have.%x\n",swap->altpayment->txbytes,swap->havestate);
}
jaddbits256(newjson,"A0",swap->mypubs[0]);
jaddbits256(newjson,"A1",swap->mypubs[1]);
9 years ago
swap->pubA0 = swap->mypubs[0];
//swap->pubA1 = swap->mypubs[1];
9 years ago
if ( bits256_nonz(swap->pubAm) == 0 && swap->otherchoosei >= 0 && bits256_nonz(swap->privkeys[swap->otherchoosei]) != 0 )
9 years ago
{
9 years ago
swap->pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey,swap->privkeys[swap->otherchoosei]);
9 years ago
swap->privAm = swap->privkeys[swap->otherchoosei];
memset(&swap->privkeys[swap->otherchoosei],0,sizeof(swap->privkeys[swap->otherchoosei]));
}
9 years ago
}
else
{
9 years ago
if ( bits256_nonz(swap->pubBn) == 0 && swap->otherchoosei >= 0 && bits256_nonz(swap->privkeys[swap->otherchoosei]) != 0 )
9 years ago
{
9 years ago
swap->pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey,swap->privkeys[swap->otherchoosei]);
9 years ago
swap->privBn = swap->privkeys[swap->otherchoosei];
memset(&swap->privkeys[swap->otherchoosei],0,sizeof(swap->privkeys[swap->otherchoosei]));
}
9 years ago
jaddbits256(newjson,"B0",swap->mypubs[0]);
jaddbits256(newjson,"B1",swap->mypubs[1]);
9 years ago
swap->pubB0 = swap->mypubs[0];
swap->pubB1 = swap->mypubs[1];
9 years ago
if ( (swap->otherhavestate & INSTANTDEX_ORDERSTATE_HAVEDEPOSIT) == 0 && swap->deposit != 0 && jobj(newjson,"deposit") == 0 )
{
jaddbits256(newjson,"deposittxid",swap->deposit->txid);
jaddstr(newjson,"deposit",swap->deposit->txbytes);
printf("add deposit.(%s) have.%x\n",swap->deposit->txbytes,swap->havestate);
}
else if ( (swap->otherhavestate & INSTANTDEX_ORDERSTATE_HAVEPAYMENT) == 0 && swap->payment != 0 && jobj(newjson,"payment") == 0 )
{
jaddbits256(newjson,"paymenttxid",swap->payment->txid);
jaddstr(newjson,"payment",swap->payment->txbytes);
printf("add payment.(%s) have.%x\n",swap->payment->txbytes,swap->havestate);
}
}
9 years ago
if ( bits256_nonz(swap->pubAm) != 0 )
jaddbits256(newjson,"pubAm",swap->pubAm);
9 years ago
if ( bits256_nonz(swap->privAm) != 0 )
jaddbits256(newjson,"privAm",swap->privAm);
9 years ago
if ( bits256_nonz(swap->pubBn) != 0 )
jaddbits256(newjson,"pubBn",swap->pubBn);
9 years ago
}
9 years ago
cJSON *instantdex_parseargjson(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,int32_t deckflag)
9 years ago
{
9 years ago
cJSON *newjson;
9 years ago
newjson = cJSON_CreateObject();
9 years ago
if ( swap == 0 )
9 years ago
jaddstr(newjson,"error","missing swap info");
else
{
9 years ago
if ( instantdex_isbob(swap) != 0 )
9 years ago
{
9 years ago
if ( jobj(argjson,"secretAm") != 0 )
decode_hex(swap->secretAm,20,jstr(argjson,"secretAm"));
9 years ago
instantdex_swapbits256update(&swap->otherpubs[0],argjson,"A0");
instantdex_swapbits256update(&swap->otherpubs[1],argjson,"A1");
9 years ago
if ( bits256_nonz(swap->otherpubs[0]) != 0 )
swap->pubA0 = swap->otherpubs[0];
//if ( bits256_nonz(swap->otherpubs[1]) != 0 )
// swap->pubA1 = swap->otherpubs[1];
9 years ago
instantdex_swapbits256update(&swap->pubAm,argjson,"pubAm");
instantdex_swapbits256update(&swap->privAm,argjson,"privAm");
9 years ago
swap->havestate |= instantdex_swaptxupdate(swap->altcoin,&swap->altpayment,argjson,"altpayment","altpaymenttxid");
9 years ago
}
else
{
9 years ago
if ( jobj(argjson,"secretBn") != 0 )
9 years ago
decode_hex(swap->secretBn,20,jstr(argjson,"secretBn"));
9 years ago
instantdex_swapbits256update(&swap->otherpubs[0],argjson,"B0");
instantdex_swapbits256update(&swap->otherpubs[1],argjson,"B1");
9 years ago
if ( bits256_nonz(swap->otherpubs[0]) != 0 )
swap->pubB0 = swap->otherpubs[0];
if ( bits256_nonz(swap->otherpubs[1]) != 0 )
swap->pubB1 = swap->otherpubs[1];
9 years ago
instantdex_swapbits256update(&swap->pubBn,argjson,"pubBn");
instantdex_swapbits256update(&swap->privBn,argjson,"privBn");
9 years ago
swap->havestate |= instantdex_swaptxupdate(swap->coinbtc,&swap->deposit,argjson,"deposit","deposittxid");
swap->havestate |= instantdex_swaptxupdate(swap->coinbtc,&swap->payment,argjson,"payment","paymenttxid");
9 years ago
}
9 years ago
swap->havestate |= instantdex_swaptxupdate(swap->coinbtc,&swap->otherfee,argjson,"feetx","feetxid");
9 years ago
if ( swap->otherchoosei < 0 && jobj(argjson,"mychoosei") != 0 )
9 years ago
{
9 years ago
printf("otherschoosei.%d\n",swap->otherchoosei);
9 years ago
if ( (swap->otherchoosei= juint(argjson,"mychoosei")) >= sizeof(swap->otherdeck)/sizeof(*swap->otherdeck) )
swap->otherchoosei = -1;
9 years ago
}
9 years ago
if ( swap->otherchoosei >= 0 )
{
char str[65],str2[65];
if ( instantdex_isbob(swap) != 0 )
{
if ( bits256_nonz(swap->pubAm) == 0 )
swap->pubAm = jbits256(argjson,"pubAm");
else if ( bits256_cmp(swap->pubAm,jbits256(argjson,"pubAm")) != 0 )
{
printf("mismatched pubAm %s vs %s\n",bits256_str(str,swap->pubAm),bits256_str(str2,jbits256(argjson,"pubAm")));
}
}
else
{
if ( bits256_nonz(swap->pubBn) == 0 )
swap->pubBn = jbits256(argjson,"pubBn");
else if ( bits256_cmp(swap->pubBn,jbits256(argjson,"pubBn")) != 0 )
{
printf("mismatched pubBn %s vs %s\n",bits256_str(str,swap->pubBn),bits256_str(str2,jbits256(argjson,"pubBn")));
}
}
}
9 years ago
if ( jobj(argjson,"mychoosei") != 0 )
{
if ( swap->otherchoosei < 0 )
swap->otherchoosei = jnum(argjson,"mychoosei");
else if ( swap->otherchoosei != jnum(argjson,"mychoosei") )
{
printf("otherchoosei mismatch %d vs %d\n",swap->otherchoosei,jnum(argjson,"mychoosei"));
}
}
9 years ago
if ( juint(argjson,"verified") != 0 )
swap->otherverifiedcut = 1;
9 years ago
if ( juint(argjson,"have") != 0 )
swap->otherhavestate |= juint(argjson,"have");
9 years ago
//printf("got other.%x myhave.%x choosei.(%d %d)\n",swap->otherhavestate,swap->havestate,swap->choosei,swap->otherchoosei);
9 years ago
}
return(newjson);
}
9 years ago
cJSON *BTC_checkdeckfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
9 years ago
*serdatap = 0, *serdatalenp = 0; struct iguana_info *coin = iguana_coinfind("BTC");
if ( coin != 0 )
9 years ago
{
9 years ago
if ( swap->choosei >= 0 && swap->otherchoosei >= 0 )
9 years ago
jaddstr(newjson,"virtevent","gotdeck");
9 years ago
}
9 years ago
return(newjson);
}
9 years ago
cJSON *BTC_waitfeefunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
*serdatap = 0, *serdatalenp = 0;
9 years ago
if ( swap->otherfee != 0 && iguana_txidstatus(swap->coinbtc,swap->otherfee->txid) >= 0. )
9 years ago
{
9 years ago
if ( instantdex_feetxverify(myinfo,swap->coinbtc,swap,argjson) < 0 )
{
printf("fee didnt verify\n");
return(cJSON_Parse("{\"error\":\"fee didnt verify\"}"));
}
9 years ago
if ( instantdex_isbob(swap) != 0 )
9 years ago
jaddstr(newjson,"virtevent","gendep");
else jaddstr(newjson,"virtevent","waitdep");
}
return(newjson);
}
cJSON *BTC_gendepositfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
int32_t i;
*serdatap = 0, *serdatalenp = 0;
if ( instantdex_isbob(swap) != 0 )
{
for (i=0; i<20; i++)
if ( swap->secretBn[i] != 0 )
break;
if ( i == 20 )
9 years ago
{
9 years ago
if ( bits256_nonz(swap->pubA0) != 0 && bits256_nonz(swap->pubB0) != 0 )
{
if ( swap->deposit == 0 && (swap->deposit= instantdex_bobtx(myinfo,swap,swap->coinbtc,swap->BTCsatoshis,1)) == 0 )
printf("bobtx deposit couldnt be created\n");
else jaddstr(newjson,"virtevent","depmade");
}
9 years ago
}
}
9 years ago
return(newjson);
9 years ago
}
9 years ago
cJSON *BTC_waitdepositfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
9 years ago
char msigaddr[64];
9 years ago
*serdatap = 0, *serdatalenp = 0;
9 years ago
if ( instantdex_isbob(swap) == 0 )
9 years ago
{
9 years ago
if ( swap->deposit != 0 && iguana_txidstatus(swap->coinbtc,swap->deposit->txid) >= swap->btcconfirms )
9 years ago
{
9 years ago
if ( instantdex_paymentverify(myinfo,swap->coinbtc,swap,argjson,1) < 0 )
9 years ago
{
printf("deposit didnt verify\n");
return(cJSON_Parse("{\"error\":\"deposit didnt verify\"}"));
}
printf("deposit verified\n");
9 years ago
if ( swap->altpayment == 0 && (swap->altpayment= instantdex_alicetx(myinfo,swap->altcoin,msigaddr,swap->pubAm,swap->pubBn,swap->altsatoshis,swap)) == 0 )
9 years ago
printf("error creating altpayment\n");
else jaddstr(newjson,"virtevent","depfound");
9 years ago
}
9 years ago
}
9 years ago
return(newjson);
}
cJSON *BTC_waitaltpaymentfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
*serdatap = 0, *serdatalenp = 0;
9 years ago
if ( swap->altpayment != 0 && iguana_txidstatus(swap->altcoin,swap->altpayment->txid) >= swap->altconfirms )
9 years ago
{
if ( instantdex_isbob(swap) != 0 )
{
9 years ago
if ( instantdex_altpaymentverify(myinfo,swap->altcoin,swap,argjson) == 0 )
9 years ago
{
9 years ago
if ( swap->payment == 0 && (swap->payment= instantdex_bobtx(myinfo,swap,swap->coinbtc,swap->BTCsatoshis,0)) == 0 )
9 years ago
printf("couldnt create Bob's payment\n");
9 years ago
jaddstr(newjson,"virtevent","altfound");
9 years ago
} else printf("alt payment didnt verify\n");
9 years ago
} else jaddstr(newjson,"virtevent","altfound");
9 years ago
}
return(newjson);
}
9 years ago
cJSON *BTC_waitpaymentfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
*serdatap = 0, *serdatalenp = 0;
9 years ago
if ( swap->payment != 0 && iguana_txidstatus(swap->coinbtc,swap->payment->txid) >= swap->btcconfirms )
9 years ago
{
9 years ago
if ( instantdex_isbob(swap) == 0 )
{
if ( instantdex_paymentverify(myinfo,iguana_coinfind(swap->mine.offer.base),swap,argjson,0) == 0 )
jaddstr(newjson,"virtevent","payfound");
} else jaddstr(newjson,"virtevent","payfound");
9 years ago
}
9 years ago
return(newjson);
9 years ago
}
9 years ago
cJSON *BTC_cashmsigfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
*serdatap = 0, *serdatalenp = 0;
return(newjson);
}
cJSON *BTC_donefunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
*serdatap = 0, *serdatalenp = 0;
9 years ago
return(newjson);
9 years ago
}
9 years ago
cJSON *BTC_cleanupfunc(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
{
*serdatap = 0, *serdatalenp = 0;
swap->dead = (uint32_t)time(NULL);
swap->mine.dead = (uint32_t)time(NULL);
swap->other.dead = (uint32_t)time(NULL);
9 years ago
portable_mutex_lock(&exchange->mutexS);
DL_DELETE(exchange->statemachines,swap);
portable_mutex_unlock(&exchange->mutexS);
instantdex_historyadd(exchange,swap);
9 years ago
printf("delete from statemachines, add to history\n");
9 years ago
return(newjson);
}
9 years ago
struct instantdex_stateinfo *BTC_initFSM(int32_t *n)
{
struct instantdex_stateinfo *s = 0;
9 years ago
// Two initial states are BOB_idle and ALICE_idle
9 years ago
// Inconvenient to start statemachines before this as typically after posting something in the orderbook, it is possible for multiple offers to come in. In that case the user or designated tradebot will need to choose among the acceptable offers and also to determine how much longer to wait. Also, an orderbook entry is technically a state, but there is no assurance it will ever proceed beyond the initial state and not just expire. Once an incoming offer is accepted, then the statemachine is created to push the swap toward completion.
// the initiator includes a deck of INSTANTDEX_DECKSIZE keypairs
9 years ago
//
9 years ago
// "BTC<msg> are message events from other party (message events capped at length 8)
// "<lowercase msg>" are special events
// <TX> types: <fee>, <dep>osit, <alt>payment, <acl> is altcoin claim, <bre>claim and <are>claim are bob's and alice's reclaiming of their payments, <bfr> and <afr>claim are bob's and alice's reclaim of fee for failed trade, <adp> is alice claiming the deposit
9 years ago
// "<TX>found" means the other party's is confirmed at user specified confidence level
9 years ago
9 years ago
// BTC_cleanup state just unwinds pending swap as nothing has been committed yet
// states instantdex_statecreate(s,n,<Name of State>,handlerfunc,errorhandler,<Timeout State>,<Error State>
9 years ago
// a given state has a couple of handlers and custom events, with timeouts and errors invoking a bypass
9 years ago
// events instantdex_addevent(s,*n,<Current State>,<event>,<message to send>,<Next State>)
9 years ago
*n = 2; // start with state 2
s = instantdex_statecreate(s,n,"BTC_cleanup",BTC_cleanupfunc,0,0,0,-1); // from states without any commits
9 years ago
memset(s,0,sizeof(*s) * 2); // make sure state 0 and 1 are cleared
9 years ago
// terminal [BLOCKING] states for the corresponding transaction
// if all goes well both alice and bob get to claim the other's payments
9 years ago
9 years ago
// after offer is sent, wait for other side to choose and sent their deck, then send privs
9 years ago
s = instantdex_statecreate(s,n,"BTC_idle",BTC_checkdeckfunc,0,"BTC_cleanup",0,1);
s = instantdex_statecreate(s,n,"BTC_waitdeck",BTC_checkdeckfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_gotdeck",BTC_checkdeckfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_waitfee",BTC_waitfeefunc,0,"BTC_cleanup",0,0);
9 years ago
s = instantdex_statecreate(s,n,"BTC_gendeposit",BTC_gendepositfunc,0,"BTC_cleanup",0,0);
9 years ago
s = instantdex_statecreate(s,n,"BTC_waitdeposit",BTC_waitdepositfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_waitaltpayment",BTC_waitaltpaymentfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_waitpayment",BTC_waitpaymentfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_makeclaim",BTC_makeclaimfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_cashmsig",BTC_cashmsigfunc,0,"BTC_cleanup",0,0);
s = instantdex_statecreate(s,n,"BTC_done",BTC_donefunc,0,"BTC_cleanup",0,0);
9 years ago
9 years ago
instantdex_addevent(s,*n,"BTC_idle","BTCoffer","poll","BTC_waitdeck"); // send deck + Chose
instantdex_addevent(s,*n,"BTC_waitdeck","gotdeck","havedeck","BTC_gotdeck"); // virt event
instantdex_addevent(s,*n,"BTC_waitdeck","havedeck","poll","BTC_waitdeck"); // other side gotdeck
instantdex_addevent(s,*n,"BTC_waitdeck","poll","poll","BTC_waitdeck");
9 years ago
9 years ago
// to goto BTC_waitfee, both must have sent/recv deck and Chosen and verified cut and choose
9 years ago
instantdex_addevent(s,*n,"BTC_gotdeck","gotdeck","sentprivs","BTC_waitfee"); // other gotdeck
instantdex_addevent(s,*n,"BTC_gotdeck","havedeck","poll","BTC_gotdeck");
9 years ago
instantdex_addevent(s,*n,"BTC_gotdeck","poll","poll","BTC_gotdeck");
9 years ago
9 years ago
// [BLOCKING: feefound] Bob waits for fee and sends deposit when it appears, alice skips past
9 years ago
instantdex_addevent(s,*n,"BTC_waitfee","gendep","poll","BTC_gendeposit"); // bob's virt
instantdex_addevent(s,*n,"BTC_waitfee","waitdep","poll","BTC_waitdeposit"); // alice's virt
9 years ago
instantdex_addevent(s,*n,"BTC_waitfee","poll","poll","BTC_waitfee");
9 years ago
instantdex_addevent(s,*n,"BTC_gendeposit","depmade","poll","BTC_waitaltpayment");
instantdex_addevent(s,*n,"BTC_gendeposit","poll","poll","BTC_gendeposit");
9 years ago
// [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment, bob skips
9 years ago
instantdex_addevent(s,*n,"BTC_waitdeposit","depfound","gotdep","BTC_waitpayment"); // alice virt
9 years ago
instantdex_addevent(s,*n,"BTC_waitdeposit","gotdep","poll","BTC_waitdeposit");
instantdex_addevent(s,*n,"BTC_waitdeposit","poll","poll","BTC_waitdeposit");
// [BLOCKING: altfound] now Bob's turn to make sure altpayment is confirmed and send payment
instantdex_addevent(s,*n,"BTC_waitaltpayment","altfound","gotalt","BTC_waitpayment"); // virt
instantdex_addevent(s,*n,"BTC_waitaltpayment","gotalt","poll","BTC_waitaltpayment");
instantdex_addevent(s,*n,"BTC_waitaltpayment","poll","poll","BTC_waitaltpayment");
9 years ago
9 years ago
// [BLOCKING: payfound] now Alice's turn to make sure payment is confrmed and send in claim or see bob's reclaim and reclaim
instantdex_addevent(s,*n,"BTC_waitpayment","payfound","gotpaytx","BTC_makeclaim"); // virt
instantdex_addevent(s,*n,"BTC_waitpayment","gotpaytx","poll","BTC_waitpayment");
instantdex_addevent(s,*n,"BTC_waitpayment","poll","poll","BTC_waitpayment");
9 years ago
9 years ago
// [BLOCKING: privM] Bob waits for privM either from Alice or alt blockchain
instantdex_addevent(s,*n,"BTC_makeclaim","claimed","didclaim","BTC_done");
instantdex_addevent(s,*n,"BTC_makeclaim","didclaim","poll","BTC_cashmsig");
instantdex_addevent(s,*n,"BTC_makeclaim","poll","poll","BTC_makeclaim");
instantdex_addevent(s,*n,"BTC_cashmsig","gotprivM","didmsig","BTC_done");
instantdex_addevent(s,*n,"BTC_cashmsig","poll","poll","BTC_cashmsig");
/*s = instantdex_statecreate(s,n,"ALICE_checkbobreclaim",ALICE_checkbobreclaimfunc,0,"ALICE_reclaimed",0,0);
9 years ago
instantdex_addevent(s,*n,"ALICE_checkbobreclaim","brefound","poll","ALICE_reclaimed");
instantdex_addevent(s,*n,"ALICE_checkbobreclaim","poll","poll","ALICE_waitconfirms");
9 years ago
s = instantdex_statecreate(s,n,"BOB_sentpayment",BOB_waitprivMfunc,0,"BOB_reclaimed",0,0);
9 years ago
instantdex_addevent(s,*n,"BOB_sentpayment","aclfound","BTCdone","BOB_claimedalt");
9 years ago
instantdex_addevent(s,*n,"BOB_sentpayment","BTCprivM","BTCdone","BOB_claimedalt");
9 years ago
instantdex_addevent(s,*n,"BOB_sentpayment","poll","poll","BOB_sentpayment");*/
{
double startmillis = OS_milliseconds();
instantdex_FSMtest(s,*n,1000);
printf("elapsed %.3f ave %.6f\n",OS_milliseconds() - startmillis,(OS_milliseconds() - startmillis)/1000);
}
9 years ago
return(s);
}
9 years ago
struct bitcoin_eventitem *instantdex_event(char *cmdstr,cJSON *argjson,cJSON *newjson,uint8_t *serdata,int32_t serdatalen)
{
struct bitcoin_eventitem *ptr;
ptr = calloc(1,sizeof(*ptr) + serdatalen);
strcpy(ptr->cmd,cmdstr);
ptr->newjson = jduplicate(newjson);
ptr->argjson = jduplicate(argjson);
if ( serdatalen != 0 )
{
memcpy(ptr->serdata,serdata,serdatalen);
ptr->serdatalen = serdatalen;
}
return(ptr);
}
9 years ago
void instantdex_eventfree(struct bitcoin_eventitem *ptr)
{
if ( ptr != 0 )
{
if ( ptr->argjson != 0 )
free_json(ptr->argjson);
if ( ptr->newjson != 0 )
free_json(ptr->newjson);
free(ptr);
}
}
9 years ago
char *instantdex_statemachine(struct instantdex_stateinfo *states,int32_t numstates,struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,char *cmdstr,cJSON *argjson,cJSON *newjson,uint8_t *serdata,int32_t serdatalen)
9 years ago
{
9 years ago
uint32_t i; struct instantdex_stateinfo *state=0;
if ( swap == 0 || (state= swap->state) == 0 )
9 years ago
{
9 years ago
printf("state.%s (%s)\n",state->name,swap->mine.offer.base);
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap missing coin info\"}"));
9 years ago
}
9 years ago
printf("%llu/%llu cmd.(%s) state.(%s) newlen.%d isbob.%d have.%x myhave.%x myfee.%p\n",(long long)swap->mine.orderid,(long long)swap->other.orderid,cmdstr,swap->state->name,(int32_t)strlen(jprint(newjson,0)),instantdex_isbob(swap),juint(argjson,"have"),swap->havestate,swap->myfee);
9 years ago
if ( jobj(argjson,"have") != 0 )
swap->otherhavestate |= juint(argjson,"have");
9 years ago
if ( jobj(argjson,"mychoosei") != 0 )
swap->otherchoosei |= juint(argjson,"mychoosei");
9 years ago
if ( swap->state->name[0] == 0 || (swap->expiration != 0 && time(NULL) > swap->expiration) )
9 years ago
{
9 years ago
swap->state = &states[state->timeoutind];
9 years ago
swap->dead = (uint32_t)time(NULL);
9 years ago
if ( state->timeout == 0 || (newjson= (*state->timeout)(myinfo,exchange,swap,argjson,newjson,&serdata,&serdatalen)) == 0 )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap null return from timeoutfunc\"}"));
9 years ago
else return(jprint(newjson,0));
9 years ago
}
for (i=0; i<state->numevents; i++)
{
if ( strcmp(cmdstr,state->events[i].cmdstr) == 0 )
{
9 years ago
if ( state->process != 0 && (newjson= (*state->process)(myinfo,exchange,swap,argjson,newjson,&serdata,&serdatalen)) == 0 )
9 years ago
{
9 years ago
if ( strcmp("poll",state->events[i].sendcmd) == 0 )
{
9 years ago
printf("POLL for pending tx\n");
9 years ago
//return(instantdex_sendcmd(myinfo,&swap->mine.offer,newjson,state->events[i].sendcmd,myinfo->myaddr.persistent,0,serdata,serdatalen,0));
9 years ago
}
else
{
printf("null return from non-poll event\n");
9 years ago
swap->state = &states[state->errorind];
9 years ago
return(clonestr("{\"error\":\"instantdex_statemachine: null return\"}"));
}
9 years ago
}
else
{
9 years ago
if ( 0 && strcmp(cmdstr,"poll") != 0 )
9 years ago
{
if ( swap->pollevent != 0 )
instantdex_eventfree(swap->pollevent);
swap->pollevent = instantdex_event("poll",argjson,newjson,serdata,serdatalen);
}
9 years ago
if ( jstr(newjson,"virtevent") != 0 )
9 years ago
{
printf("VIRTEVENT.(%s)\n",jstr(newjson,"virtevent"));
9 years ago
for (i=0; i<state->numevents; i++)
if ( strcmp(jstr(newjson,"virtevent"),state->events[i].cmdstr) == 0 )
9 years ago
{
9 years ago
cmdstr = state->events[i].cmdstr;
break;
9 years ago
}
9 years ago
if ( i == state->numevents )
{
printf("error cant find.(%s)\n",jstr(newjson,"virtevent"));
return(clonestr("{\"error\":\"instantdex_statemachine: unexpected virtevent\"}"));
}
else
{
//printf("found.%d event.%s -> %s next.%d\n",i,state->events[i].cmdstr,states[state->events[i].nextstateind].name,state->events[i].nextstateind);
9 years ago
}
9 years ago
}
9 years ago
if ( state->events[i].sendcmd[0] != 0 )
9 years ago
{
9 years ago
//printf("i.%d send.%s, next state.%s.[%d] %p\n",i,state->events[i].sendcmd,states[state->events[i].nextstateind].name,state->events[i].nextstateind,&states[state->events[i].nextstateind]);
9 years ago
if ( state->events[i].nextstateind > 1 )
9 years ago
{
9 years ago
instantdex_newjson(myinfo,swap,newjson);
9 years ago
//printf("i.%d (%s) %s %s.%d -> %s.%d send.(%s) %p\n",i,jprint(newjson,0),cmdstr,swap->state->name,state->ind,states[state->events[i].nextstateind].name,state->events[i].nextstateind,state->events[i].sendcmd,&states[state->events[i].nextstateind]);
9 years ago
swap->state = &states[state->events[i].nextstateind];
9 years ago
return(instantdex_sendcmd(myinfo,&swap->mine.offer,newjson,state->events[i].sendcmd,swap->othertrader,INSTANTDEX_HOPS,serdata,serdatalen,0,swap));
9 years ago
} else return(clonestr("{\"error\":\"instantdex_statemachine: illegal state\"}"));
9 years ago
} else return(clonestr("{\"result\":\"instantdex_statemachine: processed\"}"));
9 years ago
}
}
}
return(clonestr("{\"error\":\"instantdex_statemachine: unexpected state\"}"));
}
9 years ago
void instantdex_statemachine_iter(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap)
{
9 years ago
char *str; struct bitcoin_eventitem *ptr; cJSON *newjson; int32_t flag = 0;
9 years ago
if ( swap->dead != 0 || swap->mine.dead != 0 || swap->other.dead != 0 )
9 years ago
return;
9 years ago
if ( swap->myfee == 0 )
9 years ago
swap->myfee = instantdex_feetx(myinfo,&swap->mine,swap,swap->coinbtc);
9 years ago
//printf("state(%s) %llx/%llx\n",swap->state->name,(long long)swap->mine.orderid,(long long)swap->other.orderid);
9 years ago
while ( (ptr= queue_dequeue(&swap->eventsQ,0)) != 0 )
{
9 years ago
//printf("dequeued (%s)\n",ptr->cmd);
9 years ago
if ( (str= instantdex_statemachine(BTC_states,BTC_numstates,myinfo,exchange,swap,ptr->cmd,ptr->argjson,ptr->newjson,ptr->serdata,ptr->serdatalen)) != 0 )
9 years ago
free(str);
9 years ago
instantdex_eventfree(ptr);
flag++;
}
9 years ago
if ( flag == 0 && swap->dead == 0 && swap->pollevent != 0 )
9 years ago
{
9 years ago
//printf("send poll event\n");
9 years ago
newjson = jduplicate(swap->pollevent->newjson);
9 years ago
if ( (str= instantdex_statemachine(BTC_states,BTC_numstates,myinfo,exchange,swap,"poll",swap->pollevent->argjson,newjson,swap->pollevent->serdata,swap->pollevent->serdatalen)) != 0 )
9 years ago
free(str);
9 years ago
free_json(newjson);
9 years ago
}
}
9 years ago
#ifdef oldway
// https://github.com/TierNolan/bips/blob/bip4x/bip-atom.mediawiki
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);
9 years ago
}
/*
9 years ago
Name: Bob.Bail.In
9 years ago
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
9 years ago
Name: Alice.Bail.In
9 years ago
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
9 years ago
*/
9 years ago
char *instantdex_bailintx(struct iguana_info *coin,bits256 *txidp,struct bitcoin_spend *spend,bits256 A0,bits256 B0,uint8_t x[20],int32_t isbob)
{
9 years ago
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_txoutput(coin,txobj,scriptv0,scriptv0len,spend->satoshis);
9 years ago
if ( isbob != 0 )
{
scriptv1len = bitcoin_revealsecret160(scriptv1,0,x);
scriptv1len = bitcoin_pubkeyspend(scriptv1,scriptv1len,pubkey);
} else scriptv1len = bitcoin_p2shspend(scriptv1,0,x);
bitcoin_txoutput(coin,txobj,scriptv1,scriptv1len,spend->txfee);
9 years ago
if ( (scriptv2len= bitcoin_changescript(coin,changescript,0,&change,spend->changeaddr,spend->input_satoshis,spend->satoshis,spend->txfee)) > 0 )
bitcoin_txoutput(coin,txobj,changescript,scriptv2len,change);
9 years ago
for (i=0; i<spend->numinputs; i++)
bitcoin_txinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,0xffffffff);
9 years ago
rawtxstr = bitcoin_json2hex(coin,&txid,txobj,0);
9 years ago
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 )
9 years ago
printf("signed %s_bailin.%s (%s)\n",isbob!=0?"bob":"alice",bits256_str(str,signedtxid),signedtx);
9 years ago
else printf("error generating signedtx\n");
free_json(txobj);
*txidp = txid;
return(signedtx);
9 years ago
}
9 years ago
9 years ago
cJSON *instantdex_bailinspend(struct iguana_info *coin,bits256 privkey,uint64_t amount)
{
9 years ago
int32_t n; cJSON *txobj;
9 years ago
int32_t scriptv0len; uint8_t p2shscript[256],rmd160[20],scriptv0[128],pubkey[35];
bitcoin_pubkey33(coin->ctx,pubkey,privkey);
9 years ago
n = bitcoin_pubkeyspend(p2shscript,0,pubkey);
9 years ago
calc_rmd160_sha256(rmd160,p2shscript,n);
9 years ago
scriptv0len = bitcoin_p2shspend(scriptv0,0,rmd160);
txobj = bitcoin_createtx(coin,0);
bitcoin_txoutput(coin,txobj,scriptv0,scriptv0len,amount);
9 years ago
return(txobj);
}
/*
9 years ago
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
9 years ago
Name: Alice.Payout
9 years ago
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
*/
9 years ago
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;
9 years ago
rawtxstr = bitcoin_json2hex(coin,txidp,txobj,0);
9 years ago
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_txinput(coin,txobj,bailintxid,0,0xffffffff);
bitcoin_txinput(coin,txobj,bailintxid,1,0xffffffff);
9 years ago
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));
}
/*
9 years ago
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))
9 years ago
9 years ago
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)
*/
9 years ago
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_txinput(coin,txobj,bailintxid,0,0xffffffff);
9 years ago
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)
9 years ago
{
9 years ago
uint8_t pubkey[33],rmd160[20]; int32_t n;
9 years ago
memcpy(pubkey+1,pub.bytes,sizeof(pub)), pubkey[0] = firstbyte;
9 years ago
n = bitcoin_pubkeyspend(p2shscript,0,pubkey);
9 years ago
calc_rmd160_sha256(rmd160,p2shscript,n);
9 years ago
init_hexbytes_noT(hexstr,rmd160,sizeof(rmd160));
return(n);
}
9 years ago
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 )
{
9 years ago
if ( (spend= instantdex_spendset(myinfo,coin,A->offer.basevolume64,INSTANTDEX_DONATION)) != 0 )
9 years ago
{
bailintx = instantdex_bailintx(coin,&bailintxid,spend,A0,B0,secret160,0);
9 years ago
refundtx = instantdex_refundtx(coin,&refundtxid,sharedprivs[0],sharedprivs[2],bailintxid,A->offer.basevolume64,coin->chain->txfee,isbob);
9 years ago
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);
9 years ago
return(instantdex_sendcmd(myinfo,&A->A,newjson,nextcmd,swap->othertrader,INSTANTDEX_HOPS));
9 years ago
} 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;
9 years ago
if ( (newjson= instantdex_newjson(myinfo,A0p,B0p,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
9 years ago
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];
9 years ago
if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
9 years ago
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 )
9 years ago
return(instantdex_sendcmd(myinfo,&A->A,newjson,nextstate,swap->othertrader,INSTANTDEX_HOPS));
9 years ago
else return(clonestr("{\"result\":\"instantdex_BTCswap advance complete, wait or refund\"}"));
} else return(clonestr("{\"error\":\"instantdex_BTCswap advance cant find statusjson\"}"));
}
9 years ago
void instantdex_pendingnotice(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,uint64_t basevolume64)
9 years ago
{
// printf("need to start monitoring thread\n");
ap->pendingvolume64 -= basevolume64;
}
9 years ago
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
{
9 years ago
uint8_t secret160[20]; bits256 hash,traderpub,A0,B0,sharedprivs[4]; uint64_t satoshis[2];
9 years ago
cJSON *newjson; char *retstr=0,*str;
9 years ago
int32_t locktime,isbob=0,offerdir = 0; struct iguana_info *coinbtc,*other;
9 years ago
if ( exchange == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap null exchange ptr\"}"));
9 years ago
offerdir = instantdex_bidaskdir(A);
9 years ago
if ( (other= iguana_coinfind(A->offer.base)) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 )
9 years ago
{
9 years ago
printf("other.%p coinbtc.%p (%s/%s)\n",other,coinbtc,A->offer.base,A->offer.rel);
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap cant find btc or other coin info\"}"));
9 years ago
}
9 years ago
locktime = (uint32_t)(A->offer.expiration + INSTANTDEX_LOCKTIME);
if ( strcmp(A->offer.rel,"BTC") != 0 )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer non BTC rel\"}"));
9 years ago
vcalc_sha256(0,hash.bytes,(void *)&A->A,sizeof(ap->offer));
9 years ago
if ( hash.txid != A->orderid )
return(clonestr("{\"error\":\"txid mismatches orderid\"}"));
9 years ago
satoshis[0] = A->offer.basevolume64;
9 years ago
satoshis[1] = instantdex_BTCsatoshis(A->offer.price64,A->offer.basevolume64);
9 years ago
//printf("got offer.(%s) offerside.%d offerdir.%d\n",jprint(argjson,0),A->offer.myside,A->offer.acceptdir);
9 years ago
if ( strcmp(cmdstr,"offer") == 0 ) // sender is Bob, receiver is network (Alice)
9 years ago
{
9 years ago
if ( A->offer.expiration < (time(NULL) + INSTANTDEX_DURATION) )
9 years ago
{
printf("too close to expiration: %u >= %lu\n",A->offer.expiration,(time(NULL) + INSTANTDEX_DURATION));
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer too close to expiration\"}"));
9 years ago
}
9 years ago
if ( (ap= instantdex_acceptable(exchange,A,myinfo->myaddr.nxt64bits)) != 0 )
9 years ago
{
9 years ago
isbob = 0;
9 years ago
if ( (newjson= instantdex_newjson(myinfo,&A0,&B0,sharedprivs,secret160,isbob,argjson,hash,A)) == 0 )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
else
9 years ago
{
9 years ago
//instantdex_pendingnotice(myinfo,exchange,ap,A);
9 years ago
return(instantdex_bailinrefund(myinfo,other,exchange,A,"proposal",secret160,newjson,isbob,A0,B0,sharedprivs));
9 years ago
}
}
9 years ago
else
9 years ago
{
9 years ago
printf("Ano matching trade.(%s)\n",jprint(argjson,0));
9 years ago
if ( (str= InstantDEX_minaccept(myinfo,0,argjson,0,A->offer.base,"BTC",dstr(A->offer.price64),dstr(A->offer.basevolume64))) != 0 )
9 years ago
free(str);
9 years ago
}
9 years ago
}
9 years ago
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));
9 years ago
}
9 years ago
else if ( strcmp(cmdstr,"accept") == 0 ) // sender is Bob, receiver is Alice
9 years ago
{
9 years ago
isbob = 0;
newjson = instantdex_payout(myinfo,other,exchange,A,secret160,isbob,&A0,&B0,sharedprivs,hash,satoshis,argjson);
9 years ago
return(instantdex_sendcmd(myinfo,&A->A,newjson,"BTCconfirm",swap->othertrader,INSTANTDEX_HOPS));
9 years ago
}
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);
9 years ago
return(instantdex_sendcmd(myinfo,&A->A,newjson,"BTCbroadcast",swap->othertrader,INSTANTDEX_HOPS));
9 years ago
}
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));
9 years ago
}
9 years ago
else if ( strcmp(cmdstr,"complete") == 0 ) // sender is Bob, receiver is Alice
9 years ago
{
9 years ago
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));
9 years ago
}
else retstr = clonestr("{\"error\":\"BTC swap got unrecognized command\"}");
9 years ago
if ( retstr == 0 )
retstr = clonestr("{\"error\":\"BTC swap null retstr\"}");
9 years ago
return(retstr);
}
9 years ago
#endif