How to merge a sponsored stellar account with '0' XLM balance - merge

I create a sponsored account with '0' XLM balance. To remove it using the sponsoring account, I use the accountMerge operation, but the subsequent endSponsoringFutureReserves operation fails to access the merged account - preventing the whole transaction from running. If I create a sponsored account with '0.0002' XLM balance, I can merge it when it is the transaction's source. Can the merging be done by the sponsoring account instead? TIA

You can create a regular (non-sponsored) transaction with the account_merge operation and then wrap that transaction in a FeeBumpTransaction paid by any (e.g. the sponsoring) account.

Related

Database model design for single entry transaction between two accounts?

I am building an app that helps people transfer money from one account to another. I have two tables "Users" and "Transactions". The way I am currently handling transfers is by
Check if the sender has enough balance to make a transfer.
Deduct the balance from the sender and update the sender's balance.
Add the amount deducted from the sender's account to the recipient's account and then update the balance of the recipient.
Then finally write the transaction record on the "Transactions" table as a single entry like below:
id | transactionId | senderAccount | recipientAccount | Amount |
—--+---------------+---------------+------------------+--------+
1 | ijiej33 | A | B | 100 |
so my question is, is recording a transaction as a single entry like above a good practice or will this kind of database model design produce future challenges?
Thanks
Check if the sender has enough balance to make a transfer.
Deduct the balance from the sender and update the sender's balance.
Yes, but.
If two concurrent connections attempt to deduct money from the sender at the same time, they may both successfully check that there is enough money for each transaction on its own, then succeed even though the balance is insufficient for both transactions to succeed.
You must use a SELECT FOR UPDATE when checking. This will lock the row for the duration of the transaction (until COMMIT or ROLLBACK), and any concurrent connection attempting to also SELECT FOR UPDATE on the same row will have to wait.
Presumably the receiver account can always receive money, so there is no need to lock it explicitly, but the UPDATE will lock it anyway. And locks must always be acquired in the same order or you will get deadlocks.
For example if a transatcion locks rows 1 then 2, while another locks rows 2 then 1: the first one will lock 1, the second will lock 2, then the first will try to lock 2 but it is already locked, and the second will try to lock 1 but it is also already locked by the other transaction. Both transactions will wait for each other forever until the deadlock detector nukes one of them.
One simple way to dodge this is to use ORDER BY:
SELECT ... FROM users WHERE user_id IN (sender_id,receiver_id)
ORDER BY user_id FOR UPDATE;
This will lock both rows in the order of their user_ids, which will always be the same.
Then you can do the rest of the procedure.
Since it is always a good idea to hold locks for the shortest amount of time, I'd recommend to put the whole thing inside a plpgsql stored procedure, including the COMMIT/ROLLBACK and error handling. Try to make the stored procedure failsafe and atomic.
Note, for security purposes, you should:
Store the balance of both accounts before the money transfer occured into the transactions table. You're already SELECT'ing it in the SELECT for update, might as well use it. It will be useful for auditing.
For security, if a user gets their password stolen there's not much you can do, but if your application gets hacked it would be nice if the hacker was not able to issue global UPDATEs to all the account balances, mess with the audit tables, etc. This means you need to read up on this and create several postgres users/roles with suitable permissions for backup, web application, etc. Some tables and especially the transactions table should have all UPDATE privileges revoked, and INSERT allowed only for the transactions stored procs, for example. The aim is to make the audit tables impossible to modify, basically append-only from the point of view of the application code.
Likewise you can handle updates to balance via stored procedures and forbid the web application role from messing with it. You could even add take a user-specific security token passed as a parameter to the stored proc, to authenticate the app user to the database, so the database only allows transfers from the account of the user who is logged in, not just any user.
Basically if it involves money, then it involves legislation, and you have to think about how not to go to jail when your web app gets hacked.

How to properly account for system failure when deducting a users balance and calling a 3rd party service?

Presume a user would like to withdraw $5.00 balance on a website for PayPal balance. So they hit a withdraw endpoint which makes sure they have enough balance, calls PayPal pay api, and deducts the users on-site balance in a single serializable transaction.
What would happen if the database server drops and the transaction fails to commit after the PayPal pay request is executed successfully and the users gets their on-site balance back?
Is there a way I can encapsulate all of these calls in one atomic transaction?
I assume you are looking for two-phase commit
https://www.postgresql.org/docs/current/static/sql-prepare-transaction.html
PREPARE TRANSACTION prepares the current transaction for two-phase
commit. After this command, the transaction is no longer associated
with the current session; instead, its state is fully stored on disk,
and there is a very high probability that it can be committed
successfully, even if a database crash occurs before the commit is
requested.
Once prepared, a transaction can later be committed or rolled back
with COMMIT PREPARED or ROLLBACK PREPARED, respectively.
(empasis mine)
You shouldn't try to do this atomically. The nature of internet APIs makes this impossible.
You should probably do something resembling this pseudocode:
payment_id = random_payment_id()
try:
db:
insert into payments (payment_id, order_id, payment_amount, status, created)
values (:payment_id, :order_id, :payment_amount, 'pending', now());
commit;
remote.create_payment(payment_id, payment_amount);
except remote.error:
throw payment_error
On payment confirmation:
try:
remote.execute_payment(payment_id);
db:
update payments set status='completed' where payment_id=:payment_id;
commit;
except remote.error:
throw payment_error
And periodically you have to check a status of 'pending' payments, as you can't be sure that you'll receive all payment confirmations:
db:
select payment_id from payments
where status='pending' and created<now()-'10 minutes';
for payment_id in db.result:
if remote.payment_status(payment_id) == 'approved':
remote.execute_payment(payment_id);
db:
update payments set status='completed' where payment_id=:payment_id;
commit;
You should also periodically clean expired unconfirmed payments:
db:
select payment_id from payments
where status='pending' and created<now()-'10 days';
for payment_id in db.result:
remote.cancel_payment(payment_id);
db:
update payments set status='failed' where payment_id=:payment_id;
commit;

shopify transaction api GET all transactions

since shopify's transaction reporting is broken, I'm trying to use the API to get transaction fees for orders and basic accounting. In their API docs, they have their endpoints and parameters listed for getting/posting transactions. To "Receive a list of all Transactions", the docs say
GET /admin/orders/#{id}/transactions.json
but don't explain what the #{id} is for. The call will only work if I put a transaction ID in, but then it only shows a single transaction, rather than a list. The docs state that to "Get the Representation of a specific transaction":
GET /admin/orders/#{id}/transactions/#{id}.json
Which has the id in there twice. I can't use a single transaction, I need all of them for a specific range. I've tried /admin/orders/transactions.json, or putting in all or * in for the id, and it returns errors unless the id is a valid transaction id. Any ideas?
Transactions belong to an order. So the ID you are wondering about is for one specific order. So if you want transactions for your accounting system, the important thing you're basing your API work on will be orders. So setup your code to first off download the orders of interest. Say for a month. Now for each order ask for the transactions, and produce your report.

paypal checkout with mixed billing type products

I have, in my opinion, pretty complex order case to implement. Paypal was choosen as a solution, but I can't figure it out how to implement it properly using express checkout (or anything else, but I am not sure what is proper to use).
Final order that can consist of (most complex example here):
subscription A with 1 month free trial - 100$/year
subscription B without free trial - 200$/year
initial payment for entire order - 50$
Requirements:
start of the whole order can be postponed due to some factors (I can set PROFILESTARTDATE to the given date)
all subscriptions in the order can be either monthly or yearly, so case where subscription A is paid per year and subscription B per month IS NOT ALLOWED
whole order must be processed in one paypal redirect (paypal page with products listed where client can login to confirm the order)
My problem:
in that order subscription A starts 1 month later than B but I can only set one PROFILESTARTDATE
I could use TRIAL*** parameters (like TRIALBILLINGPERIOD) for subscription B but I can only set one such parameter per paypal request for express checkout, so same problem as above
What would be a best option for such case ?

balanceDate of an account vs postedDate of transactions in AggCat

I noticed that for an account A, the lastTransactionDate is the date such that all transactions happen before that are available through getAccountTransactions. It's NOT the date such that ONLY all transactions happen before that are taken into account when calculating the balance of account A because some transactions happen after lastTransactionDate have to be taken into account to yield the correct balance. Can someone confirm my observation?
Another thing is that some transactions that happen on the same date as balanceDate with the exact time being AFTER the time of balanceDate are taken into account as well to yield the account's balance. For example, balanceAmount = 7682.16, balanceDate = 2013-08-06 12:53:21 - 07:00 but the transaction with postedDate = 2013-08-06 16:49:41 - 07:00 is included. Does this mean we should only care about the date portion of balanceDate? and that balanceDate of 2013-08-06 12:53:21 - 07:00 includes all transactions posted on 2013-08-06?
The LastTransactionsDate is the date of the last captured transaction in our system. The balance of the account is what we captured from the FI's website so we perform no calculation of the transactions to come up with that number. If there are pending transactions and the FI provides their balance in that fashion we will provide that value.
The BalanceDate field refers to when our system captured the balance of the account from the website. So that balance would include all the transactions posted on the website at that time and if the account is including the pending transactions you would need to include those as well to match the balance appropriately.