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.
881 lines
34 KiB
881 lines
34 KiB
|
|
/******************************************************************************
|
|
* Copyright © 2014-2018 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_etomic.c
|
|
// marketmaker
|
|
//
|
|
|
|
//
|
|
// Created by artem on 24.01.18.
|
|
//
|
|
#include "LP_etomic.h"
|
|
#define ALICE_PAYMENT_SENT 1
|
|
#define BOB_DEPOSIT_SENT 1
|
|
#define BOB_PAYMENT_SENT 1
|
|
|
|
int32_t LP_etomic_wait_for_confirmation(char *txId)
|
|
{
|
|
return(waitForConfirmation(txId));
|
|
}
|
|
|
|
char *LP_etomicalice_send_fee(struct basilisk_swap *swap)
|
|
{
|
|
char amount[100], secretKey[70];
|
|
satoshisToWei(amount, LP_DEXFEE(swap->I.alicerealsat));
|
|
swap->myfee.I.eth_amount = LP_DEXFEE(swap->I.alicerealsat);
|
|
uint8arrayToHex(secretKey, swap->persistent_privkey.bytes, 32);
|
|
if (strcmp(swap->I.alicestr,"ETH") == 0 ) {
|
|
return(sendEth(INSTANTDEX_ETHADDR, amount, secretKey, 1, 0, 0, 1));
|
|
} else {
|
|
struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr);
|
|
|
|
return(sendErc20(swap->I.alicetomic, INSTANTDEX_ETHADDR, amount, secretKey, 1, 0, 0, 1, alicecoin->decimals));
|
|
}
|
|
}
|
|
|
|
uint8_t LP_etomic_verify_alice_fee(struct basilisk_swap *swap)
|
|
{
|
|
if (waitForConfirmation(swap->otherfee.I.ethTxid) < 0) {
|
|
printf("Alice fee tx %s does not exist", swap->otherfee.I.ethTxid);
|
|
return(0);
|
|
}
|
|
EthTxData data = getEthTxData(swap->otherfee.I.ethTxid);
|
|
if (compareAddresses(data.from, swap->I.etomicdest) == 0) {
|
|
printf("Alice fee tx %s was sent from wrong address %s\n", swap->otherfee.I.ethTxid, data.from);
|
|
return(0);
|
|
}
|
|
|
|
if ( strcmp(swap->I.alicestr,"ETH") == 0 ) {
|
|
if (compareAddresses(data.to, INSTANTDEX_ETHADDR) == 0 && compareAddresses(data.to, INSTANTDEX_OLD_ETHADDR) == 0) {
|
|
printf("Alice fee %s was sent to wrong address %s\n", swap->otherfee.I.ethTxid, data.to);
|
|
return(0);
|
|
}
|
|
uint64_t txValue = weiToSatoshi(data.valueHex, 18);
|
|
if (txValue != LP_DEXFEE(swap->I.alicerealsat)) {
|
|
printf("Alice fee %s amount %" PRIu64 " is not equal to expected %" PRId64 "\n", swap->otherfee.I.ethTxid, txValue, LP_DEXFEE(swap->I.alicerealsat));
|
|
return(0);
|
|
}
|
|
return(1);
|
|
} else {
|
|
struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr);
|
|
|
|
if (compareAddresses(data.to, swap->I.alicetomic) == 0) {
|
|
printf("Alice ERC20 fee %s token address %s is not equal to expected %s\n", swap->otherfee.I.ethTxid, data.to, swap->I.alicetomic);
|
|
return(0);
|
|
}
|
|
char weiAmount[70];
|
|
satoshisToWei(weiAmount, LP_DEXFEE(swap->I.alicerealsat));
|
|
uint8_t verify_new = verifyAliceErc20FeeData(swap->I.alicetomic, INSTANTDEX_ETHADDR, weiAmount, data.input, alicecoin->decimals);
|
|
uint8_t verify_old = verifyAliceErc20FeeData(swap->I.alicetomic, INSTANTDEX_OLD_ETHADDR, weiAmount, data.input, alicecoin->decimals);
|
|
return((uint8_t)(verify_new || verify_old));
|
|
}
|
|
}
|
|
|
|
char *LP_etomicalice_send_payment(struct basilisk_swap *swap)
|
|
{
|
|
AliceSendsEthPaymentInput input; AliceSendsErc20PaymentInput input20; BasicTxData txData;
|
|
swap->alicepayment.I.eth_amount = swap->I.alicerealsat;
|
|
// set input and txData fields from the swap data structure
|
|
memset(&txData,0,sizeof(txData));
|
|
if ( strcmp(swap->I.alicestr,"ETH") == 0 )
|
|
{
|
|
memset(&input,0,sizeof(input));
|
|
strcpy(input.bobAddress, swap->I.etomicsrc);
|
|
uint8arrayToHex(input.bobHash, swap->I.secretBn, 20);
|
|
uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20);
|
|
uint8arrayToHex(input.dealId, swap->alicepayment.I.actualtxid.bytes, 32);
|
|
|
|
strcpy(txData.from, swap->I.etomicdest);
|
|
strcpy(txData.to, ETOMIC_ALICECONTRACT);
|
|
satoshisToWei(txData.amount, swap->I.alicerealsat);
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
|
|
return(aliceSendsEthPayment(input,txData));
|
|
}
|
|
else
|
|
{
|
|
struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr);
|
|
|
|
memset(&input20,0,sizeof(input20));
|
|
strcpy(input20.bobAddress, swap->I.etomicsrc);
|
|
uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20);
|
|
uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20);
|
|
uint8arrayToHex(input20.dealId, swap->alicepayment.I.actualtxid.bytes, 32);
|
|
strcpy(input20.tokenAddress, swap->I.alicetomic);
|
|
satoshisToWei(input20.amount, swap->I.alicerealsat);
|
|
input20.decimals = alicecoin->decimals;
|
|
|
|
strcpy(txData.from, swap->I.etomicdest);
|
|
strcpy(txData.to, ETOMIC_ALICECONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
|
|
uint64_t allowance = getErc20Allowance(swap->I.etomicdest, ETOMIC_ALICECONTRACT, swap->I.alicetomic, alicecoin->decimals);
|
|
if (allowance < swap->I.alicerealsat) {
|
|
printf("Alice token allowance is too low, setting new allowance\n");
|
|
ApproveErc20Input approveErc20Input;
|
|
strcpy(approveErc20Input.tokenAddress, swap->I.alicetomic);
|
|
strcpy(approveErc20Input.owner, swap->I.etomicdest);
|
|
strcpy(approveErc20Input.spender, ETOMIC_ALICECONTRACT);
|
|
|
|
char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicdest, swap->I.alicetomic);
|
|
strcpy(approveErc20Input.amount, tokenBalance);
|
|
free(tokenBalance);
|
|
strcpy(approveErc20Input.secret, txData.secretKey);
|
|
|
|
char *allowTxId = approveErc20(approveErc20Input);
|
|
LP_etomic_wait_for_confirmation(allowTxId);
|
|
free(allowTxId);
|
|
}
|
|
|
|
return(aliceSendsErc20Payment(input20,txData));
|
|
}
|
|
}
|
|
|
|
uint8_t LP_etomic_verify_alice_payment(struct basilisk_swap *swap, char *txId)
|
|
{
|
|
if (waitForConfirmation(txId) < 0) {
|
|
printf("Alice payment %s does not exist\n", txId);
|
|
return(0);
|
|
}
|
|
EthTxData data = getEthTxData(txId);
|
|
if (compareAddresses(data.to, ETOMIC_ALICECONTRACT) == 0) {
|
|
printf("Alice payment %s was sent to wrong address %s\n", txId, data.to);
|
|
return(0);
|
|
}
|
|
if (compareAddresses(data.from, swap->I.etomicdest) == 0) {
|
|
printf("Alice payment %s was done from wrong address %s\n", txId, data.from);
|
|
return(0);
|
|
}
|
|
AliceSendsEthPaymentInput input; AliceSendsErc20PaymentInput input20;
|
|
if ( strcmp(swap->I.alicestr,"ETH") == 0 ) {
|
|
uint64_t paymentAmount = weiToSatoshi(data.valueHex, 18);
|
|
if (paymentAmount != swap->I.alicerealsat) {
|
|
printf("Alice payment amount %" PRIu64 " does not match expected %" PRIu64 "\n", paymentAmount, swap->I.alicerealsat);
|
|
return(0);
|
|
}
|
|
memset(&input,0,sizeof(input));
|
|
strcpy(input.bobAddress, swap->I.etomicsrc);
|
|
uint8arrayToHex(input.bobHash, swap->I.secretBn, 20);
|
|
uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20);
|
|
uint8arrayToHex(input.dealId, swap->alicepayment.I.actualtxid.bytes, 32);
|
|
|
|
return(verifyAliceEthPaymentData(input, data.input));
|
|
} else {
|
|
struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr);
|
|
|
|
memset(&input20,0,sizeof(input20));
|
|
strcpy(input20.bobAddress, swap->I.etomicsrc);
|
|
uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20);
|
|
uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20);
|
|
uint8arrayToHex(input20.dealId, swap->alicepayment.I.actualtxid.bytes, 32);
|
|
strcpy(input20.tokenAddress, swap->I.alicetomic);
|
|
satoshisToWei(input20.amount, swap->I.alicerealsat);
|
|
input20.decimals = alicecoin->decimals;
|
|
|
|
return(verifyAliceErc20PaymentData(input20, data.input));
|
|
}
|
|
}
|
|
|
|
char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_ALICEPAYMENT]) < 0) {
|
|
printf("Alice ETH payment %s is not found, can't reclaim\n", swap->eth_tx_ids[BASILISK_ALICEPAYMENT]);
|
|
return NULL;
|
|
}
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_ALICEPAYMENT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Alice payment receipt status failed, can't reclaim\n");
|
|
return NULL;
|
|
}
|
|
AliceReclaimsAlicePaymentInput input;
|
|
BasicTxData txData;
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
|
|
struct iguana_info *ecoin, *alice_coin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
alice_coin = LP_coinfind(swap->dest);
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
uint8arrayToHex(input.dealId, swap->txids[BASILISK_ALICEPAYMENT].bytes, 32);
|
|
if (alicePaymentStatus(input.dealId + 2) != ALICE_PAYMENT_SENT) {
|
|
printf("Alice payment smart contract status check failed, can't spend\n");
|
|
return NULL;
|
|
}
|
|
satoshisToWei(input.amount, swap->alicerealsat);
|
|
|
|
if (swap->alicetomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->alicetomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
strcpy(input.bobAddress, swap->etomicsrc);
|
|
uint8arrayToHex(input.aliceHash, swap->secretAm, 20);
|
|
bits256 invertedSecret;
|
|
int32_t i;
|
|
for (i=0; i<32; i++) {
|
|
invertedSecret.bytes[i] = swap->privBn.bytes[31 - i];
|
|
}
|
|
uint8arrayToHex(input.bobSecret, invertedSecret.bytes, 32);
|
|
|
|
input.decimals = alice_coin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicdest);
|
|
strcpy(txData.to, ETOMIC_ALICECONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return aliceReclaimsAlicePayment(input, txData);
|
|
}
|
|
|
|
char *LP_etomicbob_spends_alice_payment(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_ALICEPAYMENT]) < 0) {
|
|
printf("Alice ETH payment %s is not found, can't spend\n", swap->eth_tx_ids[BASILISK_ALICEPAYMENT]);
|
|
return NULL;
|
|
}
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_ALICEPAYMENT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Alice payment receipt status failed, can't spend\n");
|
|
return NULL;
|
|
}
|
|
BobSpendsAlicePaymentInput input;
|
|
BasicTxData txData;
|
|
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
|
|
struct iguana_info *ecoin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
uint8arrayToHex(input.dealId, swap->txids[BASILISK_ALICEPAYMENT].bytes, 32);
|
|
if (alicePaymentStatus(input.dealId + 2) != ALICE_PAYMENT_SENT) {
|
|
printf("Alice payment smart contract status check failed, can't spend\n");
|
|
return NULL;
|
|
}
|
|
|
|
satoshisToWei(input.amount, swap->alicerealsat);
|
|
|
|
if (swap->alicetomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->alicetomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
|
|
strcpy(input.aliceAddress, swap->etomicdest);
|
|
bits256 invertedSecret; int32_t i;
|
|
for (i=0; i<32; i++) {
|
|
invertedSecret.bytes[i] = swap->privAm.bytes[31 - i];
|
|
}
|
|
uint8arrayToHex(input.aliceSecret, invertedSecret.bytes, 32);
|
|
uint8arrayToHex(input.bobHash, swap->secretBn, 20);
|
|
struct iguana_info *alice_coin = LP_coinfind(swap->dest);
|
|
input.decimals = alice_coin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicsrc);
|
|
strcpy(txData.to, ETOMIC_ALICECONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return bobSpendsAlicePayment(input, txData);
|
|
}
|
|
|
|
char *LP_etomicbob_sends_deposit(struct basilisk_swap *swap)
|
|
{
|
|
BobSendsEthDepositInput input;
|
|
BobSendsErc20DepositInput input20;
|
|
BasicTxData txData;
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
memset(&input20,0,sizeof(input20));
|
|
if ( strcmp(swap->I.bobstr,"ETH") == 0 ) {
|
|
uint8arrayToHex(input.depositId, swap->bobdeposit.I.actualtxid.bytes, 32);
|
|
strcpy(input.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input.bobHash, swap->I.secretBn, 20);
|
|
input.lockTime = swap->bobdeposit.I.locktime;
|
|
|
|
strcpy(txData.from, swap->I.etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
satoshisToWei(txData.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat));
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
return bobSendsEthDeposit(input, txData);
|
|
} else {
|
|
struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr);
|
|
|
|
uint8arrayToHex(input20.depositId, swap->bobdeposit.I.actualtxid.bytes, 32);
|
|
strcpy(input20.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20);
|
|
satoshisToWei(input20.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat));
|
|
strcpy(input20.tokenAddress, swap->I.bobtomic);
|
|
input20.lockTime = swap->bobdeposit.I.locktime;
|
|
input20.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->I.etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
|
|
uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic, bobcoin->decimals);
|
|
if (allowance < LP_DEPOSITSATOSHIS(swap->I.bobrealsat)) {
|
|
printf("Bob token allowance is too low, setting new allowance\n");
|
|
ApproveErc20Input approveErc20Input;
|
|
strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic);
|
|
strcpy(approveErc20Input.owner, swap->I.etomicsrc);
|
|
strcpy(approveErc20Input.spender, ETOMIC_BOBCONTRACT);
|
|
|
|
char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicsrc, swap->I.bobtomic);
|
|
strcpy(approveErc20Input.amount, tokenBalance);
|
|
free(tokenBalance);
|
|
strcpy(approveErc20Input.secret, txData.secretKey);
|
|
|
|
char *allowTxId = approveErc20(approveErc20Input);
|
|
LP_etomic_wait_for_confirmation(allowTxId);
|
|
free(allowTxId);
|
|
}
|
|
|
|
return bobSendsErc20Deposit(input20, txData);
|
|
}
|
|
}
|
|
|
|
uint8_t LP_etomic_verify_bob_deposit(struct basilisk_swap *swap, char *txId)
|
|
{
|
|
if (waitForConfirmation(txId) < 0) {
|
|
printf("Bob deposit txid %s does not exist\n", txId);
|
|
return(0);
|
|
}
|
|
EthTxData data = getEthTxData(txId);
|
|
if (compareAddresses(data.to, ETOMIC_BOBCONTRACT) == 0) {
|
|
printf("Bob deposit txid %s was sent to wrong address %s\n", txId, data.to);
|
|
return(0);
|
|
}
|
|
if (compareAddresses(data.from, swap->I.etomicsrc) == 0) {
|
|
printf("Bob deposit txid %s was sent from wrong address %s\n", txId, data.from);
|
|
return(0);
|
|
}
|
|
BobSendsEthDepositInput input;
|
|
BobSendsErc20DepositInput input20;
|
|
memset(&input,0,sizeof(input));
|
|
memset(&input20,0,sizeof(input20));
|
|
if ( strcmp(swap->I.bobstr,"ETH") == 0 ) {
|
|
uint64_t depositAmount = weiToSatoshi(data.valueHex, 18);
|
|
if (depositAmount != LP_DEPOSITSATOSHIS(swap->I.bobrealsat)) {
|
|
printf("Bob deposit %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, depositAmount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat));
|
|
return(0);
|
|
}
|
|
uint8arrayToHex(input.depositId, swap->bobdeposit.I.actualtxid.bytes, 32);
|
|
strcpy(input.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input.bobHash, swap->I.secretBn, 20);
|
|
input.lockTime = swap->bobdeposit.I.locktime;
|
|
|
|
return verifyBobEthDepositData(input, data.input);
|
|
} else {
|
|
struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr);
|
|
|
|
uint8arrayToHex(input20.depositId, swap->bobdeposit.I.actualtxid.bytes, 32);
|
|
strcpy(input20.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20);
|
|
satoshisToWei(input20.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat));
|
|
strcpy(input20.tokenAddress, swap->I.bobtomic);
|
|
input20.lockTime = swap->bobdeposit.I.locktime;
|
|
input20.decimals = bobcoin->decimals;
|
|
|
|
return verifyBobErc20DepositData(input20, data.input);
|
|
}
|
|
}
|
|
|
|
char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_BOBDEPOSIT]) < 0) {
|
|
printf("Bob deposit %s is not found, can't refund\n", swap->eth_tx_ids[BASILISK_BOBDEPOSIT]);
|
|
return NULL;
|
|
}
|
|
BobRefundsDepositInput input;
|
|
BasicTxData txData;
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
|
|
struct iguana_info *ecoin, *bobcoin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
bobcoin = LP_coinfind(swap->src);
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_BOBDEPOSIT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Bob deposit %s receipt status failed, can't refund\n", swap->eth_tx_ids[BASILISK_BOBDEPOSIT]);
|
|
return NULL;
|
|
}
|
|
uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32);
|
|
if (bobDepositStatus(input.depositId + 2) != BOB_DEPOSIT_SENT) {
|
|
printf("Bob deposit smart contract status check failed, can't claim\n");
|
|
return NULL;
|
|
}
|
|
|
|
strcpy(input.aliceAddress, swap->etomicdest);
|
|
|
|
bits256 invertedSecret;
|
|
int32_t i;
|
|
for (i=0; i<32; i++) {
|
|
invertedSecret.bytes[i] = swap->privBn.bytes[31 - i];
|
|
}
|
|
uint8arrayToHex(input.bobSecret, invertedSecret.bytes, 32);
|
|
|
|
if (swap->bobtomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->bobtomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
satoshisToWei(input.amount, LP_DEPOSITSATOSHIS(swap->bobrealsat));
|
|
input.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return bobRefundsDeposit(input, txData);
|
|
}
|
|
|
|
char *LP_etomicbob_sends_payment(struct basilisk_swap *swap)
|
|
{
|
|
BobSendsEthPaymentInput input;
|
|
BobSendsErc20PaymentInput input20;
|
|
BasicTxData txData;
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
memset(&input20,0,sizeof(input20));
|
|
|
|
if ( strcmp(swap->I.bobstr,"ETH") == 0 ) {
|
|
uint8arrayToHex(input.paymentId, swap->bobpayment.I.actualtxid.bytes, 32);
|
|
strcpy(input.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20);
|
|
input.lockTime = swap->bobpayment.I.locktime;
|
|
|
|
strcpy(txData.from, swap->I.etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
satoshisToWei(txData.amount, swap->I.bobrealsat);
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
return bobSendsEthPayment(input, txData);
|
|
} else {
|
|
struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr);
|
|
|
|
uint8arrayToHex(input20.paymentId, swap->bobpayment.I.actualtxid.bytes, 32);
|
|
strcpy(input20.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20);
|
|
satoshisToWei(input20.amount, swap->I.bobrealsat);
|
|
strcpy(input20.tokenAddress, swap->I.bobtomic);
|
|
input20.lockTime = swap->bobpayment.I.locktime;
|
|
input20.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->I.etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32);
|
|
|
|
uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic, bobcoin->decimals);
|
|
if (allowance < swap->I.bobrealsat) {
|
|
printf("Bob token allowance is too low, setting new allowance\n");
|
|
ApproveErc20Input approveErc20Input;
|
|
strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic);
|
|
strcpy(approveErc20Input.owner, swap->I.etomicsrc);
|
|
strcpy(approveErc20Input.spender, ETOMIC_BOBCONTRACT);
|
|
|
|
char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicsrc, swap->I.bobtomic);
|
|
strcpy(approveErc20Input.amount, tokenBalance);
|
|
free(tokenBalance);
|
|
strcpy(approveErc20Input.secret, txData.secretKey);
|
|
|
|
char *allowTxId = approveErc20(approveErc20Input);
|
|
LP_etomic_wait_for_confirmation(allowTxId);
|
|
free(allowTxId);
|
|
}
|
|
|
|
return bobSendsErc20Payment(input20, txData);
|
|
}
|
|
}
|
|
|
|
uint8_t LP_etomic_verify_bob_payment(struct basilisk_swap *swap, char *txId)
|
|
{
|
|
if (waitForConfirmation(txId) < 0) {
|
|
printf("Bob payment %s is not found\n", txId);
|
|
return 0;
|
|
}
|
|
EthTxData data = getEthTxData(txId);
|
|
if (compareAddresses(data.to, ETOMIC_BOBCONTRACT) == 0) {
|
|
printf("Bob payment %s was sent to wrong address %s\n", txId, data.to);
|
|
}
|
|
if (compareAddresses(data.from, swap->I.etomicsrc) == 0) {
|
|
printf("Bob payment %s was sent from wrong address %s\n", txId, data.from);
|
|
}
|
|
BobSendsEthPaymentInput input;
|
|
BobSendsErc20PaymentInput input20;
|
|
memset(&input,0,sizeof(input));
|
|
memset(&input20,0,sizeof(input20));
|
|
if ( strcmp(swap->I.bobstr,"ETH") == 0 ) {
|
|
uint64_t paymentAmount = weiToSatoshi(data.valueHex, 18);
|
|
if (paymentAmount != swap->I.bobrealsat) {
|
|
printf("Bob payment %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, paymentAmount, swap->I.bobrealsat);
|
|
return(0);
|
|
}
|
|
uint8arrayToHex(input.paymentId, swap->bobpayment.I.actualtxid.bytes, 32);
|
|
strcpy(input.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20);
|
|
input.lockTime = swap->bobpayment.I.locktime;
|
|
|
|
return verifyBobEthPaymentData(input, data.input);
|
|
} else {
|
|
struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr);
|
|
|
|
uint8arrayToHex(input20.paymentId, swap->bobpayment.I.actualtxid.bytes, 32);
|
|
strcpy(input20.aliceAddress, swap->I.etomicdest);
|
|
uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20);
|
|
satoshisToWei(input20.amount, swap->I.bobrealsat);
|
|
strcpy(input20.tokenAddress, swap->I.bobtomic);
|
|
input20.lockTime = swap->bobpayment.I.locktime;
|
|
input20.decimals = bobcoin->decimals;
|
|
|
|
return verifyBobErc20PaymentData(input20, data.input);
|
|
}
|
|
}
|
|
|
|
char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_BOBPAYMENT]) < 0) {
|
|
printf("Bob payment %s is not found, can't reclaim\n", swap->eth_tx_ids[BASILISK_BOBPAYMENT]);
|
|
return NULL;
|
|
}
|
|
BobReclaimsBobPaymentInput input;
|
|
BasicTxData txData;
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
|
|
struct iguana_info *ecoin, *bobcoin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
bobcoin = LP_coinfind(swap->src);
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_BOBPAYMENT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Bob payment receipt status failed, can't reclaim\n");
|
|
return NULL;
|
|
}
|
|
uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32);
|
|
if (bobPaymentStatus(input.paymentId + 2) != BOB_PAYMENT_SENT) {
|
|
printf("Bob payment smart contract status check failed, can't spend\n");
|
|
return NULL;
|
|
}
|
|
strcpy(input.aliceAddress, swap->etomicdest);
|
|
uint8arrayToHex(input.aliceHash, swap->secretAm, 20);
|
|
|
|
if (swap->bobtomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->bobtomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
satoshisToWei(input.amount, swap->bobrealsat);
|
|
input.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicsrc);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return bobReclaimsBobPayment(input, txData);
|
|
}
|
|
|
|
char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_BOBPAYMENT]) < 0) {
|
|
printf("Bob payment %s is not found, can't spend\n", swap->eth_tx_ids[BASILISK_BOBPAYMENT]);
|
|
return NULL;
|
|
}
|
|
AliceSpendsBobPaymentInput input;
|
|
BasicTxData txData;
|
|
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_BOBPAYMENT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Bob payment %s receipt status failed, can't spend\n", swap->eth_tx_ids[BASILISK_BOBPAYMENT]);
|
|
return NULL;
|
|
}
|
|
struct iguana_info *ecoin, *bobcoin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
bobcoin = LP_coinfind(swap->src);
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32);
|
|
if (bobPaymentStatus(input.paymentId + 2) != BOB_PAYMENT_SENT) {
|
|
printf("Bob payment smart contract status check failed, can't spend\n");
|
|
return NULL;
|
|
}
|
|
satoshisToWei(input.amount, swap->bobrealsat);
|
|
|
|
if (swap->bobtomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->bobtomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
|
|
strcpy(input.bobAddress, swap->etomicsrc);
|
|
bits256 invertedSecret; int32_t i;
|
|
|
|
for (i=0; i<32; i++) {
|
|
invertedSecret.bytes[i] = swap->privAm.bytes[31 - i];
|
|
}
|
|
uint8arrayToHex(input.aliceSecret, invertedSecret.bytes, 32);
|
|
input.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicdest);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return aliceSpendsBobPayment(input, txData);
|
|
}
|
|
|
|
char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap)
|
|
{
|
|
if (waitForConfirmation(swap->eth_tx_ids[BASILISK_BOBDEPOSIT]) < 0) {
|
|
printf("Bob deposit %s is not found, can't claim\n", swap->eth_tx_ids[BASILISK_BOBDEPOSIT]);
|
|
return NULL;
|
|
}
|
|
AliceClaimsBobDepositInput input;
|
|
BasicTxData txData;
|
|
|
|
memset(&txData,0,sizeof(txData));
|
|
memset(&input,0,sizeof(input));
|
|
EthTxReceipt receipt = getEthTxReceipt(swap->eth_tx_ids[BASILISK_BOBDEPOSIT]);
|
|
if (strcmp(receipt.status, "0x1") != 0) {
|
|
printf("Bob deposit receipt status failed, can't claim\n");
|
|
return NULL;
|
|
}
|
|
|
|
struct iguana_info *ecoin, *bobcoin;
|
|
bits256 privkey;
|
|
ecoin = LP_coinfind("ETOMIC");
|
|
bobcoin = LP_coinfind(swap->src);
|
|
privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr);
|
|
|
|
uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32);
|
|
if (bobDepositStatus(input.depositId + 2) != BOB_DEPOSIT_SENT) {
|
|
printf("Bob deposit smart contract status check failed, can't claim\n");
|
|
return NULL;
|
|
}
|
|
|
|
satoshisToWei(input.amount, LP_DEPOSITSATOSHIS(swap->bobrealsat));
|
|
|
|
if (swap->bobtomic[0] != 0) {
|
|
strcpy(input.tokenAddress, swap->bobtomic);
|
|
} else {
|
|
strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000");
|
|
}
|
|
|
|
strcpy(input.bobAddress, swap->etomicsrc);
|
|
uint8arrayToHex(input.bobHash, swap->secretBn, 20);
|
|
input.decimals = bobcoin->decimals;
|
|
|
|
strcpy(txData.from, swap->etomicdest);
|
|
strcpy(txData.to, ETOMIC_BOBCONTRACT);
|
|
strcpy(txData.amount, "0");
|
|
uint8arrayToHex(txData.secretKey, privkey.bytes, 32);
|
|
return aliceClaimsBobDeposit(input, txData);
|
|
}
|
|
|
|
char *sendEthTx(struct basilisk_swap *swap, struct basilisk_rawtx *rawtx)
|
|
{
|
|
if (rawtx == &swap->alicepayment && swap->I.alicetomic[0] != 0) {
|
|
return LP_etomicalice_send_payment(swap);
|
|
} else if (rawtx == &swap->bobdeposit && swap->I.bobtomic[0] != 0) {
|
|
return LP_etomicbob_sends_deposit(swap);
|
|
} else if (rawtx == &swap->bobpayment && swap->I.bobtomic[0] != 0) {
|
|
return LP_etomicbob_sends_payment(swap);
|
|
} else if (swap->I.iambob == 0 && rawtx == &swap->myfee && swap->I.alicetomic[0] != 0) {
|
|
return LP_etomicalice_send_fee(swap);
|
|
} else {
|
|
char *result = malloc(67);
|
|
strcpy(result, EMPTY_ETH_TX_ID);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
int32_t LP_etomic_priv2addr(char *coinaddr,bits256 privkey)
|
|
{
|
|
char str[65],*addrstr;
|
|
bits256_str(str,privkey);
|
|
if ( (addrstr= privKey2Addr(str)) != 0 )
|
|
{
|
|
strcpy(coinaddr,addrstr);
|
|
free(addrstr);
|
|
return(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
int32_t LP_etomic_priv2pub(uint8_t *pub64,bits256 privkey)
|
|
{
|
|
char *pubstr,str[72]; int32_t retval = -1;
|
|
bits256_str(str,privkey);
|
|
if ( (pubstr= getPubKeyFromPriv(str)) != 0 )
|
|
{
|
|
if ( strlen(pubstr) == 130 && pubstr[0] == '0' && pubstr[1] == 'x' )
|
|
{
|
|
decode_hex(pub64,64,pubstr+2);
|
|
retval = 0;
|
|
}
|
|
free(pubstr);
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t LP_etomic_pub2addr(char *coinaddr,uint8_t pub64[64])
|
|
{
|
|
char pubkeystr[131],*addrstr;
|
|
strcpy(pubkeystr,"0x");
|
|
init_hexbytes_noT(pubkeystr+2,pub64,64);
|
|
if ( (addrstr= pubKey2Addr(pubkeystr)) != 0 )
|
|
{
|
|
strcpy(coinaddr,addrstr);
|
|
free(addrstr);
|
|
return(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
uint8_t LP_etomic_is_empty_tx_id(char *txId)
|
|
{
|
|
if (txId[0] == 0 || strcmp(txId, EMPTY_ETH_TX_ID) == 0) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint64_t LP_etomic_get_balance(struct iguana_info *coin, char *coinaddr, int *error)
|
|
{
|
|
if (coin->etomic[0] == 0) {
|
|
printf("Trying to get etomic balance for non-etomic coin %s!", coin->symbol);
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(coin->symbol, "ETH") == 0) {
|
|
return getEthBalance(coinaddr, error);
|
|
} else {
|
|
return getErc20BalanceSatoshi(coinaddr, coin->etomic, coin->decimals, error);
|
|
}
|
|
}
|
|
|
|
void LP_etomic_process_tx_history_json(struct iguana_info *coin, cJSON *transactions) {
|
|
int history_size = cJSON_GetArraySize(transactions);
|
|
struct LP_tx_history_item *iter;
|
|
for (int i = history_size - 1; i >= 0; i--) {
|
|
cJSON *transaction = jitem(transactions, i);
|
|
char *tx_hash = jstr(transaction, "hash");
|
|
int found = 0;
|
|
portable_mutex_lock(&coin->tx_history_mutex);
|
|
DL_FOREACH(coin->tx_history, iter) {
|
|
if (strcmp(iter->txid, tx_hash) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
portable_mutex_unlock(&coin->tx_history_mutex);
|
|
if (found || juint(transaction, "confirmations") == 0) {
|
|
continue;
|
|
}
|
|
struct LP_tx_history_item *item = malloc(sizeof(struct LP_tx_history_item));
|
|
memset(item, 0, sizeof(struct LP_tx_history_item));;
|
|
|
|
strcpy(item->txid, jstr(transaction, "hash"));
|
|
strcpy(item->category, "receive");
|
|
if (compareAddresses(coin->smartaddr, jstr(transaction, "from"))) {
|
|
strcpy(item->category, "send");
|
|
}
|
|
if (strcmp(item->category, "receive") == 0) {
|
|
item->amount = dstr(weiToSatoshi(jstr(transaction, "value"), coin->decimals));
|
|
} else {
|
|
item->amount = 0. - dstr(weiToSatoshi(jstr(transaction, "value"), coin->decimals));
|
|
}
|
|
item->time = juint(transaction, "timestamp");
|
|
strcpy(item->blockhash, jstr(transaction, "blockHash"));
|
|
item->blockindex = juint(transaction, "blockNumber");
|
|
item->blocktime = juint(transaction, "timestamp");
|
|
portable_mutex_lock(&coin->tx_history_mutex);
|
|
DL_APPEND(coin->tx_history, item);
|
|
portable_mutex_unlock(&coin->tx_history_mutex);
|
|
}
|
|
}
|
|
|
|
void LP_etomic_txhistory_loop(void *_coin)
|
|
{
|
|
struct iguana_info *coin = _coin;
|
|
if (coin->etomic[0] == 0) {
|
|
printf("Calling ETOMIC tx history loop for non-ETOMIC coin %s\n", coin->symbol);
|
|
return;
|
|
}
|
|
|
|
while (coin != NULL && coin->inactive == 0) {
|
|
coin->height = (int32_t) getEthBlockNumber();
|
|
char *result;
|
|
cJSON *json;
|
|
if (strcmp(coin->symbol, "ETH") == 0) {
|
|
// process standard transfers
|
|
result = eth_tx_history_etherscan(coin->smartaddr);
|
|
if (result) {
|
|
json = cJSON_Parse(result);
|
|
if (json) {
|
|
if (is_cJSON_Array(jobj(json, "result"))) {
|
|
LP_etomic_process_tx_history_json(coin, jobj(json, "result"));
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(result);
|
|
}
|
|
|
|
// process "internal" transactions - transactions received during smart contract executions
|
|
// these are not added to standard list to extra processing is required
|
|
result = internal_eth_tx_history_etherscan(coin->smartaddr);
|
|
if (result) {
|
|
json = cJSON_Parse(result);
|
|
if (json) {
|
|
if (is_cJSON_Array(jobj(json, "result"))) {
|
|
LP_etomic_process_tx_history_json(coin, jobj(json, "result"));
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(result);
|
|
}
|
|
} else {
|
|
result = erc20_tx_history_etherscan(coin->smartaddr, coin->etomic);
|
|
if (result) {
|
|
json = cJSON_Parse(result);
|
|
if (json) {
|
|
if (is_cJSON_Array(jobj(json, "result"))) {
|
|
LP_etomic_process_tx_history_json(coin, jobj(json, "result"));
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(result);
|
|
}
|
|
}
|
|
int (*ptr)(struct LP_tx_history_item*, struct LP_tx_history_item*) = &history_item_cmp;
|
|
struct LP_tx_history_item *_tmp;
|
|
portable_mutex_lock(&coin->tx_history_mutex);
|
|
DL_SORT(coin->tx_history, ptr);
|
|
portable_mutex_unlock(&coin->tx_history_mutex);
|
|
sleep(30);
|
|
}
|
|
}
|
|
|