private static void CheckColdStorageRecurse(FinancialAccount parent, Dictionary <string, int> addressAccountLookup)
        {
            foreach (FinancialAccount child in parent.Children)
            {
                CheckColdStorageRecurse(child, addressAccountLookup);
            }

            // After recursing, get all transactions for this account and verify against our records

            // is the account name a valid bitcoin address on the main network?

            string address = parent.BitcoinAddress;

            if (string.IsNullOrEmpty(address))
            {
                if (BitcoinUtility.IsValidBitcoinAddress(parent.Name.Trim()))
                {
                    parent.BitcoinAddress = address = parent.Name.Trim();
                }
                else
                {
                    return; // not a bitcoin address but something else; do not process
                }
            }

            Organization organization = parent.Organization;
            bool         organizationLedgerUsesBitcoin = organization.Currency.IsBitcoinCore;

            JObject addressData = JObject.Parse(
                new WebClient().DownloadString("https://blockchain.info/address/" + address +
                                               "?format=json&api_key=" +
                                               SystemSettings.BlockchainSwarmopsApiKey));

            //int transactionCount = (int) (addressData["n_tx"]);

            foreach (JObject txJson in addressData["txs"])
            {
                FinancialTransaction      ourTx          = null;
                Dictionary <Int64, Int64> satoshisLookup = new Dictionary <long, long>(); // map from ledgercents to satoshis
                BlockchainTransaction     blockchainTx   = BlockchainTransaction.FromBlockchainInfoJson(txJson);

                try
                {
                    ourTx = FinancialTransaction.FromBlockchainHash(parent.Organization, blockchainTx.TransactionHash);
                    // If the transaction was fetched fine, we have already seen this transaction, but need to re-check it
                }
                catch (ArgumentException)
                {
                    // We didn't have this transaction, so we need to create it

                    ourTx = FinancialTransaction.Create(parent.Organization, blockchainTx.TransactionDateTimeUtc, "Blockchain tx");
                    ourTx.BlockchainHash = blockchainTx.TransactionHash;

                    // Did we lose or gain money?
                    // Find all in- and outpoints, determine which are ours (hot and cold wallet) and which aren't
                }

                Dictionary <int, long> transactionReconstructedRows = new Dictionary <int, long>();

                // Note the non-blockchain rows in this tx, keep them for reconstruction

                foreach (FinancialTransactionRow row in ourTx.Rows)
                {
                    if (!addressAccountLookup.ContainsValue(row.FinancialAccountId))  // not optimal but n is small
                    {
                        // This is not a bitcoin address account, so note it for reconstruction

                        if (!transactionReconstructedRows.ContainsKey(row.FinancialAccountId))
                        {
                            transactionReconstructedRows[row.FinancialAccountId] = 0; // init
                        }

                        transactionReconstructedRows[row.FinancialAccountId] += row.AmountCents;
                    }
                    else
                    {
                        // this is a known blockchain row, note its ledgered value in satoshis
                        if (!organizationLedgerUsesBitcoin)
                        {
                            Money nativeMoney = row.AmountForeignCents;
                            if (nativeMoney != null && nativeMoney.Currency.IsBitcoinCore) // it damn well should be, but just checking
                            {
                                satoshisLookup[row.AmountCents] = row.AmountForeignCents.Cents;
                            }
                        }
                    }
                }

                // Reconstruct the blockchain rows: input, output, fees, in that order

                // -- inputs

                foreach (BlockchainTransactionRow inputRow in blockchainTx.Inputs)
                {
                    if (addressAccountLookup.ContainsKey(inputRow.Address))
                    {
                        // this input is ours

                        int financialAccountId = addressAccountLookup[inputRow.Address];

                        if (!transactionReconstructedRows.ContainsKey(financialAccountId))
                        {
                            transactionReconstructedRows[financialAccountId] = 0; // initialize
                        }

                        if (organizationLedgerUsesBitcoin)
                        {
                            transactionReconstructedRows[financialAccountId] +=
                                -inputRow.ValueSatoshis; // note the negation!
                        }
                        else
                        {
                            Int64 ledgerCents =
                                new Money(inputRow.ValueSatoshis, Currency.BitcoinCore, ourTx.DateTime).ToCurrency(
                                    organization.Currency).Cents;
                            transactionReconstructedRows[financialAccountId] +=
                                -ledgerCents; // note the negation!
                            satoshisLookup[ledgerCents] = inputRow.ValueSatoshis;
                        }
                    }
                }

                // -- outputs

                foreach (BlockchainTransactionRow outputRow in blockchainTx.Outputs)
                {
                    if (addressAccountLookup.ContainsKey(outputRow.Address))
                    {
                        // this output is ours

                        int financialAccountId = addressAccountLookup[outputRow.Address];

                        if (!transactionReconstructedRows.ContainsKey(financialAccountId))
                        {
                            transactionReconstructedRows[financialAccountId] = 0; // initialize
                        }

                        if (organizationLedgerUsesBitcoin)
                        {
                            transactionReconstructedRows[financialAccountId] +=
                                outputRow.ValueSatoshis;
                        }
                        else
                        {
                            Int64 ledgerCents =
                                new Money(outputRow.ValueSatoshis, Currency.BitcoinCore, ourTx.DateTime).ToCurrency(
                                    organization.Currency).Cents;
                            transactionReconstructedRows[financialAccountId] +=
                                ledgerCents;
                            satoshisLookup[ledgerCents] = outputRow.ValueSatoshis;
                        }
                    }
                }

                // -- fees

                if (addressAccountLookup.ContainsKey(blockchainTx.Inputs[0].Address))
                {
                    // if the first input is ours, we're paying the fee (is there any case where this is not true?)

                    if (organizationLedgerUsesBitcoin)
                    {
                        transactionReconstructedRows[organization.FinancialAccounts.CostsBitcoinFees.Identity] =
                            blockchainTx.FeeSatoshis;
                    }
                    else
                    {
                        Int64 feeLedgerCents =
                            new Money(blockchainTx.FeeSatoshis, Currency.BitcoinCore,
                                      blockchainTx.TransactionDateTimeUtc).ToCurrency(organization.Currency).Cents;
                        transactionReconstructedRows[organization.FinancialAccounts.CostsBitcoinFees.Identity] =
                            feeLedgerCents;
                    }
                }


                // Rewrite the transaction (called always, but the function won't do anything if everything matches)

                ourTx.RecalculateTransaction(transactionReconstructedRows, /* loggingPerson*/ null);

                // Finally, add foreign cents, if any

                if (!organizationLedgerUsesBitcoin)
                {
                    foreach (FinancialTransactionRow row in ourTx.Rows)
                    {
                        if (addressAccountLookup.ContainsValue(row.Account.Identity))  // "ContainsValue" is bad, but n is low
                        {
                            // Do we have a foreign amount for this row already?

                            Money foreignMoney = row.AmountForeignCents;
                            if (foreignMoney == null || foreignMoney.Cents == 0)
                            {
                                // no we didn't; create one

                                if (satoshisLookup.ContainsKey(row.AmountCents))
                                {
                                    row.AmountForeignCents = new Money(satoshisLookup[row.AmountCents], Currency.BitcoinCore, ourTx.DateTime);
                                }
                                else if (satoshisLookup.ContainsKey(-row.AmountCents))  // the negative counterpart
                                {
                                    row.AmountForeignCents = new Money(-satoshisLookup[-row.AmountCents], Currency.BitcoinCore, ourTx.DateTime);
                                }
                                else
                                {
                                    // There's a last case which may happen if the row is an addition to a previous row; if so, calculate
                                    row.AmountForeignCents = new Money(row.AmountCents, organization.Currency, ourTx.DateTime).ToCurrency(Currency.BitcoinCore);
                                }
                            }
                        }
                    }
                }
            }
        }