/** * Loads a CarePackage object from a string. */ tABC_CC ABC_CarePackageDecode(tABC_CarePackage **ppSelf, char *szCarePackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_CarePackage *pSelf = NULL; json_t *pJSON_Root = NULL; json_t *pJSON_SNRP2 = NULL; json_t *pJSON_SNRP3 = NULL; json_t *pJSON_SNRP4 = NULL; int e; // Allocate self: ABC_NEW(pSelf, tABC_CarePackage); // Parse the JSON: json_error_t error; pJSON_Root = json_loads(szCarePackage, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing CarePackage JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing CarePackage JSON"); // Unpack the contents: e = json_unpack(pJSON_Root, "{s:o, s:o, s:o, s?o}", JSON_ACCT_SNRP2_FIELD, &pJSON_SNRP2, JSON_ACCT_SNRP3_FIELD, &pJSON_SNRP3, JSON_ACCT_SNRP4_FIELD, &pJSON_SNRP4, JSON_ACCT_ERQ_FIELD, &pSelf->ERQ); ABC_CHECK_SYS(!e, "Error parsing CarePackage JSON"); // Decode SNRP's: ABC_CHECK_RET(ABC_CryptoCreateSNRPForServer(&pSelf->pSNRP1, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP2, &pSelf->pSNRP2, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP3, &pSelf->pSNRP3, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP4, &pSelf->pSNRP4, pError)); // Save everything: if (pSelf->ERQ) json_incref(pSelf->ERQ); *ppSelf = pSelf; pSelf = NULL; exit: if (pSelf) ABC_CarePackageFree(pSelf); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Loads a LoginPackage object from a string. */ tABC_CC ABC_LoginPackageDecode(tABC_LoginPackage **ppSelf, char *szLoginPackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_LoginPackage *pSelf = NULL; json_t *pJSON_Root = NULL; int e; // Allocate self: ABC_NEW(pSelf, tABC_LoginPackage); // Parse the JSON: json_error_t error; pJSON_Root = json_loads(szLoginPackage, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing LoginPackage JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing LoginPackage JSON"); // Unpack the contents: e = json_unpack(pJSON_Root, "{s?o, s?o, s:o, s?o, s?o}", JSON_ACCT_EMK_LP2_FIELD, &pSelf->EMK_LP2, JSON_ACCT_EMK_LRA3_FIELD, &pSelf->EMK_LRA3, JSON_ACCT_ESYNCKEY_FIELD, &pSelf->ESyncKey, JSON_ACCT_ELP1_FIELD, &pSelf->ELP1, JSON_ACCT_ELRA1_FIELD, &pSelf->ELRA1); ABC_CHECK_SYS(!e, "Error parsing LoginPackage JSON"); // Save everything: if (pSelf->EMK_LP2) json_incref(pSelf->EMK_LP2); if (pSelf->EMK_LRA3) json_incref(pSelf->EMK_LRA3); if (pSelf->ESyncKey) json_incref(pSelf->ESyncKey); if (pSelf->ELP1) json_incref(pSelf->ELP1); if (pSelf->ELRA1) json_incref(pSelf->ELRA1); *ppSelf = pSelf; pSelf = NULL; exit: if (pSelf) ABC_LoginPackageFree(pSelf); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
static tABC_CC ABC_BridgeDoSweep(WatcherInfo *watcherInfo, PendingSweep& sweep, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; char *szID = NULL; char *szAddress = NULL; uint64_t funds = 0; abcd::unsigned_transaction utx; bc::transaction_output_type output; abcd::key_table keys; std::string malTxId, txId; // Find utxos for this address: auto utxos = watcherInfo->watcher.get_utxos(sweep.address); // Bail out if there are no funds to sweep: if (!utxos.size()) { // Tell the GUI if there were funds in the past: if (watcherInfo->watcher.db().has_history(sweep.address)) { if (sweep.fCallback) { sweep.fCallback(ABC_CC_Ok, NULL, 0); } else { if (watcherInfo->fAsyncCallback) { tABC_AsyncBitCoinInfo info; info.eventType = ABC_AsyncEventType_IncomingSweep; info.sweepSatoshi = 0; info.szTxID = NULL; watcherInfo->fAsyncCallback(&info); } } sweep.done = true; } return ABC_CC_Ok; } // There are some utxos, so send them to ourselves: tABC_TxDetails details; memset(&details, 0, sizeof(tABC_TxDetails)); details.amountSatoshi = 0; details.amountCurrency = 0; details.amountFeesAirbitzSatoshi = 0; details.amountFeesMinersSatoshi = 0; details.szName = const_cast<char*>(""); details.szCategory = const_cast<char*>(""); details.szNotes = const_cast<char*>(""); details.attributes = 0x2; // Create a new receive request: ABC_CHECK_RET(ABC_TxCreateReceiveRequest(watcherInfo->wallet, &details, &szID, false, pError)); ABC_CHECK_RET(ABC_TxGetRequestAddress(watcherInfo->wallet, szID, &szAddress, pError)); // Build a transaction: utx.tx.version = 1; utx.tx.locktime = 0; for (auto &utxo : utxos) { bc::transaction_input_type input; input.sequence = 0xffffffff; input.previous_output = utxo.point; funds += utxo.value; utx.tx.inputs.push_back(input); } if (10000 < funds) funds -= 10000; // Ugh, hard-coded mining fee ABC_CHECK_ASSERT(!outputIsDust(funds), ABC_CC_InsufficientFunds, "Not enough funds"); output.value = funds; ABC_CHECK_NEW(outputScriptForAddress(output.script, szAddress)); utx.tx.outputs.push_back(output); // Now sign that: keys[sweep.address] = sweep.key; ABC_CHECK_SYS(abcd::gather_challenges(utx, watcherInfo->watcher), "gather_challenges"); ABC_CHECK_SYS(abcd::sign_tx(utx, keys), "sign_tx"); // Send: { bc::data_chunk raw_tx(satoshi_raw_size(utx.tx)); bc::satoshi_save(utx.tx, raw_tx.begin()); ABC_CHECK_NEW(broadcastTx(raw_tx)); } // Save the transaction in the database: malTxId = bc::encode_hash(bc::hash_transaction(utx.tx)); txId = ABC_BridgeNonMalleableTxId(utx.tx); ABC_CHECK_RET(ABC_TxSweepSaveTransaction(watcherInfo->wallet, txId.c_str(), malTxId.c_str(), funds, &details, pError)); // Done: if (sweep.fCallback) { sweep.fCallback(ABC_CC_Ok, txId.c_str(), output.value); } else { if (watcherInfo->fAsyncCallback) { tABC_AsyncBitCoinInfo info; info.eventType = ABC_AsyncEventType_IncomingSweep; info.sweepSatoshi = output.value; info.szTxID = stringCopy(txId); watcherInfo->fAsyncCallback(&info); ABC_FREE_STR(info.szTxID); } } sweep.done = true; watcherInfo->watcher.send_tx(utx.tx); exit: ABC_FREE_STR(szID); ABC_FREE_STR(szAddress); return cc; }