/** * Gets the specified field from a json string */ tABC_CC ABC_UtilGetIntValueFromJSONString(const char *szJSON, const char *szFieldName, int *pValue, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(pValue); // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_number(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON int value"); *pValue = (int) json_integer_value(pJSON_Value); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Gets the specified field from a json string * the user is responsible for free'ing the value */ tABC_CC ABC_UtilGetStringValueFromJSONString(const char *szJSON, const char *szFieldName, char **pszValue, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(pszValue); // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(*pszValue, json_string_value(pJSON_Value)); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Gets the specified field from a json string * the user is responsible for free'ing the array */ tABC_CC ABC_UtilGetArrayValuesFromJSONString(const char *szJSON, const char *szFieldName, char ***aszValues, unsigned int *pCount, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; char **pArrayStrings = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(aszValues); *aszValues = NULL; ABC_CHECK_NULL(pCount); *pCount = 0; // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_array(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array *pCount = (int) json_array_size(pJSON_Value); if (*pCount > 0) { ABC_ARRAY_NEW(pArrayStrings, *pCount, char*); for (unsigned i = 0; i < *pCount; i++) { json_t *pJSON_Elem = json_array_get(pJSON_Value, i); ABC_CHECK_ASSERT((pJSON_Elem && json_is_string(pJSON_Elem)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pArrayStrings[i], json_string_value(pJSON_Elem)); } *aszValues = pArrayStrings; pArrayStrings = NULL; }
/** * Serializes a LoginPackage object to a JSON string. */ tABC_CC ABC_LoginPackageEncode(tABC_LoginPackage *pSelf, char **pszLoginPackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; // Build the main body: pJSON_Root = json_object(); ABC_CHECK_NULL(pJSON_Root); // Write master key: if (pSelf->EMK_LP2) { ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_EMK_LP2_FIELD, pSelf->EMK_LP2)); } if (pSelf->EMK_LRA3) { ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_EMK_LRA3_FIELD, pSelf->EMK_LRA3)); } // Write sync key: ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_ESYNCKEY_FIELD, pSelf->ESyncKey)); // Write server keys: if (pSelf->ELP1) { ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_ELP1_FIELD, pSelf->ELP1)); } if (pSelf->ELRA1) { ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_ELRA1_FIELD, pSelf->ELRA1)); } // Write out: *pszLoginPackage = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_INDENT(4) | JSON_PRESERVE_ORDER); ABC_CHECK_NULL(*pszLoginPackage); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Serializes a CarePackage object to a JSON string. */ tABC_CC ABC_CarePackageEncode(tABC_CarePackage *pSelf, char **pszCarePackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_SNRP2 = NULL; json_t *pJSON_SNRP3 = NULL; json_t *pJSON_SNRP4 = NULL; // Build the SNRP's: ABC_CHECK_RET(ABC_CryptoCreateJSONObjectSNRP(pSelf->pSNRP2, &pJSON_SNRP2, pError)); ABC_CHECK_RET(ABC_CryptoCreateJSONObjectSNRP(pSelf->pSNRP3, &pJSON_SNRP3, pError)); ABC_CHECK_RET(ABC_CryptoCreateJSONObjectSNRP(pSelf->pSNRP4, &pJSON_SNRP4, pError)); // Build the main body: pJSON_Root = json_pack("{s:O, s:O, s:O}", JSON_ACCT_SNRP2_FIELD, pJSON_SNRP2, JSON_ACCT_SNRP3_FIELD, pJSON_SNRP3, JSON_ACCT_SNRP4_FIELD, pJSON_SNRP4); ABC_CHECK_NULL(pJSON_Root); // Build the ERQ, if any: if (pSelf->ERQ) { ABC_CHECK_JSON(json_object_set(pJSON_Root, JSON_ACCT_ERQ_FIELD, pSelf->ERQ)); } // Write out: *pszCarePackage = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_INDENT(4) | JSON_PRESERVE_ORDER); ABC_CHECK_NULL(*pszCarePackage); exit: if (pJSON_Root) json_decref(pJSON_Root); if (pJSON_SNRP2) json_decref(pJSON_SNRP2); if (pJSON_SNRP3) json_decref(pJSON_SNRP3); if (pJSON_SNRP4) json_decref(pJSON_SNRP4); return cc; }
/** * Creates a JSON string representing an array of values with their name */ tABC_CC ABC_UtilCreateArrayJSONObject(char **aszValues, unsigned int count, const char *szFieldName, json_t **ppJSON_Data, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *jsonItems = NULL; json_t *jsonItemArray = NULL; ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(ppJSON_Data); // create the json object that will be our questions jsonItems = json_object(); jsonItemArray = json_array(); // if there are values if ((count > 0) && (aszValues != NULL)) { for (unsigned i = 0; i < count; i++) { json_array_append_new(jsonItemArray, json_string(aszValues[i])); } } // set our final json for the array element json_object_set(jsonItems, szFieldName, jsonItemArray); *ppJSON_Data = jsonItems; jsonItems = NULL; exit: if (jsonItems) json_decref(jsonItems); if (jsonItemArray) json_decref(jsonItemArray); return cc; }
/** * Creates the json package with a single field and its int value */ tABC_CC ABC_UtilCreateIntJSONString(int value, const char *szFieldName, char **pszJSON, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(pszJSON); // create the jansson object pJSON_Root = json_pack("{si}", szFieldName, value); *pszJSON = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_INDENT(4) | JSON_PRESERVE_ORDER); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Load the general info. * * This function will load the general info which includes information on * Obelisk Servers, AirBitz fees and miners fees. */ tABC_CC ABC_GeneralGetInfo(tABC_GeneralInfo **ppInfo, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; char *szInfoFilename = NULL; tABC_GeneralInfo *pInfo = NULL; json_t *pJSON_MinersFeesArray = NULL; json_t *pJSON_AirBitzFees = NULL; json_t *pJSON_ObeliskArray = NULL; json_t *pJSON_SyncArray = NULL; bool bExists = false; ABC_CHECK_NULL(ppInfo); // get the info filename ABC_CHECK_RET(ABC_GeneralGetInfoFilename(&szInfoFilename, pError)); // check to see if we have the file ABC_CHECK_RET(ABC_FileIOFileExists(szInfoFilename, &bExists, pError)); if (false == bExists) { // pull it down from the server ABC_CHECK_RET(ABC_GeneralUpdateInfo(pError)); } // load the json ABC_CHECK_RET(ABC_FileIOReadFileObject(szInfoFilename, &pJSON_Root, true, pError)); // allocate the struct ABC_NEW(pInfo, tABC_GeneralInfo); // get the miners fees array pJSON_MinersFeesArray = json_object_get(pJSON_Root, JSON_INFO_MINERS_FEES_FIELD); ABC_CHECK_ASSERT((pJSON_MinersFeesArray && json_is_array(pJSON_MinersFeesArray)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array pInfo->countMinersFees = (unsigned int) json_array_size(pJSON_MinersFeesArray); if (pInfo->countMinersFees > 0) { ABC_ARRAY_NEW(pInfo->aMinersFees, pInfo->countMinersFees, tABC_GeneralMinerFee*); }
/** * Create a label based off the user settings * * @param pszLabel The label will be returned in this parameter * @param pError A pointer to the location to store the error if there is one */ static tABC_CC ABC_TxBuildFromLabel(Wallet &self, const char **pszLabel, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; ABC_SET_ERR_CODE(pError, ABC_CC_Ok); AutoFree<tABC_AccountSettings, ABC_FreeAccountSettings> pSettings; ABC_CHECK_NULL(pszLabel); *pszLabel = NULL; ABC_CHECK_RET(ABC_AccountSettingsLoad(self.account, &pSettings.get(), pError)); if (pSettings->bNameOnPayments && pSettings->szFullName) { *pszLabel = stringCopy(pSettings->szFullName); } exit: return cc; }
/** * Loads the settings for a specific account using the given key * If no settings file exists for the given user, defaults are created * * @param login Access to the account sync dir * @param ppSettings Location to store ptr to allocated settings (caller must free) * @param pError A pointer to the location to store the error if there is one */ tABC_CC ABC_AccountSettingsLoad(const Login &login, tABC_AccountSettings **ppSettings, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; AutoCoreLock lock(gCoreMutex); tABC_AccountSettings *pSettings = NULL; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; bool bExists = false; auto filename = login.syncDir() + ACCOUNT_SETTINGS_FILENAME; ABC_CHECK_NULL(ppSettings); ABC_CHECK_RET(ABC_FileIOFileExists(filename.c_str(), &bExists, pError)); if (true == bExists) { // load and decrypted the file into a json object ABC_CHECK_RET(ABC_CryptoDecryptJSONFileObject(filename.c_str(), toU08Buf(login.dataKey()), &pJSON_Root, pError)); //ABC_DebugLog("Loaded settings JSON:\n%s\n", json_dumps(pJSON_Root, JSON_INDENT(4) | JSON_PRESERVE_ORDER)); // allocate the new settings object ABC_NEW(pSettings, tABC_AccountSettings); pSettings->szFirstName = NULL; pSettings->szLastName = NULL; pSettings->szNickname = NULL; // get the first name pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_FIRST_NAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szFirstName, json_string_value(pJSON_Value)); } // get the last name pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_LAST_NAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szLastName, json_string_value(pJSON_Value)); } // get the nickname pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NICKNAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szNickname, json_string_value(pJSON_Value)); } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_PIN_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szPIN, json_string_value(pJSON_Value)); } // get name on payments option pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NAME_ON_PAYMENTS_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bNameOnPayments = json_is_true(pJSON_Value) ? true : false; // get minutes auto logout pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_MINUTES_AUTO_LOGOUT_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->minutesAutoLogout = (int) json_integer_value(pJSON_Value); pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_RECOVERY_REMINDER_COUNT); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->recoveryReminderCount = (int) json_integer_value(pJSON_Value); } else { pSettings->recoveryReminderCount = 0; } // get language pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_LANGUAGE_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szLanguage, json_string_value(pJSON_Value)); // get currency num pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NUM_CURRENCY_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->currencyNum = (int) json_integer_value(pJSON_Value); // get advanced features pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_ADVANCED_FEATURES_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bAdvancedFeatures = json_is_true(pJSON_Value) ? true : false; pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DAILY_SPEND_LIMIT_ENABLED); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bDailySpendLimit = json_is_true(pJSON_Value) ? true : false; } else { pSettings->bDailySpendLimit = false; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DAILY_SPEND_LIMIT_SATOSHIS); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON daily spend satoshi value"); pSettings->dailySpendLimitSatoshis = (int64_t) json_integer_value(pJSON_Value); } else { pSettings->dailySpendLimitSatoshis = 0; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_SPEND_REQUIRE_PIN_ENABLED); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bSpendRequirePin = json_is_true(pJSON_Value) ? true : false; } else { // Default to PIN required pSettings->bSpendRequirePin = true; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DISABLE_PIN_LOGIN); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bDisablePINLogin = json_is_true(pJSON_Value) ? true : false; } else { // Default to PIN login allowed pSettings->bDisablePINLogin = false; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_PIN_LOGIN_COUNT); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON pin login count"); pSettings->pinLoginCount = json_integer_value(pJSON_Value); } else { // Default to PIN login allowed pSettings->pinLoginCount = 0; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_SPEND_REQUIRE_PIN_SATOSHIS); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON daily spend satoshi value"); pSettings->spendRequirePinSatoshis = (int64_t) json_integer_value(pJSON_Value); } else { // Default PIN requirement to 50mb pSettings->spendRequirePinSatoshis = DEF_REQUIRE_PIN_SATOSHIS; } // get the denomination object json_t *pJSON_Denom = json_object_get(pJSON_Root, JSON_ACCT_BITCOIN_DENOMINATION_FIELD); ABC_CHECK_ASSERT((pJSON_Denom && json_is_object(pJSON_Denom)), ABC_CC_JSONError, "Error parsing JSON object value"); // get denomination satoshi display size (e.g., 100,000 would be milli-bit coin) pJSON_Value = json_object_get(pJSON_Denom, JSON_ACCT_SATOSHI_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->bitcoinDenomination.satoshi = json_integer_value(pJSON_Value); // get denomination type pJSON_Value = json_object_get(pJSON_Denom, JSON_ACCT_LABEL_TYPE); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->bitcoinDenomination.denominationType = json_integer_value(pJSON_Value); // get the exchange rates array json_t *pJSON_Sources = json_object_get(pJSON_Root, JSON_ACCT_EX_RATE_SOURCES_FIELD); ABC_CHECK_ASSERT((pJSON_Sources && json_is_array(pJSON_Sources)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array pSettings->exchangeRateSources.numSources = (int) json_array_size(pJSON_Sources); if (pSettings->exchangeRateSources.numSources > 0) { ABC_ARRAY_NEW(pSettings->exchangeRateSources.aSources, pSettings->exchangeRateSources.numSources, tABC_ExchangeRateSource*); }
/** * Creates the wallet with the given info. * * @param pszUUID Pointer to hold allocated pointer to UUID string */ tABC_CC ABC_WalletCreate(tABC_SyncKeys *pKeys, tABC_U08Buf L1, tABC_U08Buf LP1, const char *szUserName, const char *szWalletName, int currencyNum, unsigned int attributes, char **pszUUID, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; char *szFilename = NULL; char *szJSON = NULL; char *szUUID = NULL; char *szWalletDir = NULL; json_t *pJSON_Data = NULL; json_t *pJSON_Wallets = NULL; tABC_U08Buf WalletAcctKey = ABC_BUF_NULL; tWalletData *pData = NULL; ABC_CHECK_NULL(pszUUID); // create a new wallet data struct ABC_NEW(pData, tWalletData); pData->archived = 0; // create wallet guid ABC_CHECK_RET(ABC_CryptoGenUUIDString(&szUUID, pError)); ABC_STRDUP(pData->szUUID, szUUID); ABC_STRDUP(*pszUUID, szUUID); // generate the master key for this wallet - MK_<Wallet_GUID1> ABC_CHECK_RET(ABC_CryptoCreateRandomData(WALLET_KEY_LENGTH, &pData->MK, pError)); // create and set the bitcoin private seed for this wallet ABC_CHECK_RET(ABC_CryptoCreateRandomData(WALLET_BITCOIN_PRIVATE_SEED_LENGTH, &pData->BitcoinPrivateSeed, pError)); // Create Wallet Repo key ABC_CHECK_RET(ABC_CryptoCreateRandomData(SYNC_KEY_LENGTH, &WalletAcctKey, pError)); ABC_CHECK_RET(ABC_CryptoHexEncode(WalletAcctKey, &(pData->szWalletAcctKey), pError)); // create the wallet root directory if necessary ABC_CHECK_RET(ABC_WalletCreateRootDir(pError)); // create the wallet directory - <Wallet_UUID1> <- All data in this directory encrypted with MK_<Wallet_UUID1> ABC_CHECK_RET(ABC_WalletGetDirName(&(pData->szWalletDir), pData->szUUID, pError)); ABC_CHECK_RET(ABC_FileIOCreateDir(pData->szWalletDir, pError)); ABC_STRDUP(szWalletDir, pData->szWalletDir); // create the wallet sync dir under the main dir ABC_CHECK_RET(ABC_WalletGetSyncDirName(&(pData->szWalletSyncDir), pData->szUUID, pError)); ABC_CHECK_RET(ABC_FileIOCreateDir(pData->szWalletSyncDir, pError)); // we now have a new wallet so go ahead and cache its data ABC_CHECK_RET(ABC_WalletAddToCache(pData, pError)); // all the functions below assume the wallet is in the cache or can be loaded into the cache // set the wallet name ABC_CHECK_RET(ABC_WalletSetName(ABC_WalletID(pKeys, szUUID), szWalletName, pError)); // set the currency ABC_CHECK_RET(ABC_WalletSetCurrencyNum(ABC_WalletID(pKeys, szUUID), currencyNum, pError)); // Request remote wallet repo ABC_CHECK_RET(ABC_WalletServerRepoPost(L1, LP1, pData->szWalletAcctKey, ABC_SERVER_WALLET_CREATE_PATH, pError)); // set this account for the wallet's first account ABC_CHECK_RET(ABC_WalletAddAccount(ABC_WalletID(pKeys, szUUID), szUserName, pError)); // TODO: should probably add the creation date to optimize wallet export (assuming it is even used) // Init the git repo and sync it int dirty; ABC_CHECK_RET(ABC_SyncMakeRepo(pData->szWalletSyncDir, pError)); ABC_CHECK_RET(ABC_SyncRepo(pData->szWalletSyncDir, pData->szWalletAcctKey, &dirty, pError)); // Actiate the remote wallet ABC_CHECK_RET(ABC_WalletServerRepoPost(L1, LP1, pData->szWalletAcctKey, ABC_SERVER_WALLET_ACTIVATE_PATH, pError)); // If everything worked, add the wallet to the account: tABC_AccountWalletInfo info; // No need to free this info.szUUID = szUUID; info.MK = pData->MK; info.BitcoinSeed = pData->BitcoinPrivateSeed; info.SyncKey = WalletAcctKey; info.archived = 0; ABC_CHECK_RET(ABC_AccountWalletList(pKeys, NULL, &info.sortIndex, pError)); ABC_CHECK_RET(ABC_AccountWalletSave(pKeys, &info, pError)); // Now the wallet is written to disk, generate some addresses ABC_CHECK_RET(ABC_TxCreateInitialAddresses(ABC_WalletID(pKeys, pData->szUUID), pError)); // After wallet is created, sync the account, ignoring any errors tABC_Error Error; ABC_CHECK_RET(ABC_SyncRepo(pKeys->szSyncDir, pKeys->szSyncKey, &dirty, &Error)); pData = NULL; // so we don't free what we just added to the cache exit: if (cc != ABC_CC_Ok) { if (szUUID) { ABC_WalletRemoveFromCache(szUUID, NULL); } if (szWalletDir) { ABC_FileIODeleteRecursive(szWalletDir, NULL); } } ABC_FREE_STR(szWalletDir); ABC_FREE_STR(szFilename); ABC_FREE_STR(szJSON); ABC_FREE_STR(szUUID); if (pJSON_Data) json_decref(pJSON_Data); if (pJSON_Wallets) json_decref(pJSON_Wallets); if (pData) ABC_WalletFreeData(pData); return cc; }