How to deal when testing with eth brownie for a sender with not enough balance - brownie

I'm trying in my tests to simulate a situation where a sender calls a payable method of a contract but does not have enough balance.
A sample code would be:
with brownie.reverts():
contract.buy({'from': accounts[0], 'value': 100000000000000000000000000})
Instead of the test continuing I get a ValueError:
E ValueError: sender doesn't have enough funds to send tx. The upfront cost is: 100000000000000000000000000 and the sender's account only has: 100000000000000000000
How do I catch such errors with brownie?

You try to send more eth than is on account balance. If you use use ganache-cli the initial balance of each account is 100 eth. You can create account of bigger balance by collecting all eth into single account, as follow:
Create following brownie-config.yaml:
networks:
default: development
development:
cmd_settings:
accounts: 50
where you can change 50 to your desired number. Then create script.py file in scripts/ directory with following code:
from brownie import accounts, Wei
def main():
print('initial number of accounts ', len(accounts))
balance = accounts[0].balance()
print('initial balance of account_0 in Eth ', Wei(balance).to('ether'))
# transfer all eth into account_0
for i in range(1, len(accounts)):
amount = accounts[i].balance()
accounts[i].transfer(accounts[0], amount)
balance = accounts[0].balance()
print('final balance of account_0 in Eth ', Wei(balance).to('ether'))
Run:
brownie run scripts/script.py
to check final balance of accounts[0] EOA
Warning: It loops over all accounts and make transfer for each of them, so for big accounts number script can run really slow

Related

Rate limiting a Flask API by user_id from server session

I am trying to setup a Flask API limiter for each user. The following code limits an IP Address to 3 request per minute.
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
key_func=get_remote_address, #limit by IP Address
storage_uri="redis://localhost:6379",
strategy="moving-window"
)
#api.route('/api/submit-code')
#limiter.limit('3 per minute')
def submit_code():
user_id = session.get("user_id")
if not user_id:
return jsonify({"error": "Unauthorized"}), 401
How can I change this to limit the user instead of IP address? I am using server sessions so I'm not sure how to include user_id in the limiter decorator.
I ended up modifying the decorator to the following:
#limiter.limit('3 per minute', key_func = lambda : session.get("user_id"))
The limiter will not apply to users that are not logged in. You can simply add a check in the function for this like the OP.

Djstripe: ensuring new subscription payment succeeds before confirming successful subscription to customer

We use Djstripe to create Stripe subscriptions on our Django site like so:
# Create the Stripe subscription
stripe_subscription = stripe.Subscription.create(
customer=customer_id,
items=[{'price': plan_id}],
expand=['latest_invoice.payment_intent'],
metadata=metadata,
)
# Sync subscription from Stripe
subscription = Subscription.sync_from_stripe_data(stripe_subscription)
The process on Stripe's end seems to be something like:
Create the subscription (return status 200)
Create the payment intent object that will charge the customer for the subscription
Attempt to charge the customer
If the charge fails, put the subscription to status "incomplete"
Naively, when we get 200 back from step (1), we proceed as if the payment went through ok, but sometimes it doesn't (step (4) happens).
What is a good way to confirm a successful subscription creation to the customer oly if the subsequent charge succeeds?

How mock stripe in Django unit test

We used stripe for the payment system.
Imagine a user is doing different things in our system and for each part, he has to pay. We send these payments to Stripe by calling:
stripe.InvoiceItem.create()
Then we create and finalize the invoice for him by calling:
invoice=stripe.Invoice.create()
stripe.Invoice.finalize_invoice(invoice.id)
So if the user has to pay for 3 items:
item1 = 1
item2 = 2
item3 = 3
The finalize_invoice will have an id, total, ...., and:
total = 6
To test if all items are sending the correct amount to Stripe, I'd like to check the total.
In order to test our payment system, I had to mock Stripe, but the Stripe invoice total would always be zero.
I mocked stripe.InvoiceItem.create and stripe.Invoice.finalize_invoice and stripe.Invoice.create like this:
#patch("app_name.models.stripe.InvoiceItem.create")
#patch("app_name.models.stripe.Invoice.finalize_invoice")
#patch("app_name.models.stripe.Invoice.create")
def test_method(
self,
mock_create,
mock_finalize,
mock_invoice_item,
):
response = MagicMock()
# api_key and stripe_account from this link https://stripe.com/docs/api/connected_accounts
response.api_key = "sk_test_MSc53AbTknQXPy"
response.stripe_account = "acct_1032D82eZvKYlo2C" # Stripe account ID
# last version here https://stripe.com/docs/upgrades
response.stripe_version = "2022-08-01"
mock_invoice_item.return_value = response
response = MagicMock()
response.total = 20
response.invoice_pdf = "https://google.com"
response.id = "sk_test_MSc53AbTknQXPy"
mock_create.return_value = response
mock_finalize.return_value = response.id
Stripe might have a mocking feature.
Stripe-mock was not clear to me how to use it in unit tests.
I really don't know how you are mocking the different Stripe functions in order to pinpoint the issue with the the invoice total cost.
If you're thinking of using stripe-mock, I guess the best way to handle unit testing is to do so in an agnostic way (regardless of the stack), by running the stripe-mock Docker as described in the github Readme and create a proxy that will route any API call to the Docker URL instead of the actual API URL (https://api.stripe.com). This will allow you to do unit testing locally on your machine and even with your preferred CI/CD.
With that being said, please bear in mind that there are some known limitations described in the Readme doc.

Sending tokens out on coinpayments success payment using Web3py

I'm writing Django app and want to send out tokens using Web3 once Coinpayments sends me callback about successfull payment. The problem is that Coinpayments sends multiple callbacks at once and just in one case tokens are sending, other callbacks get replacement transaction underpriced error. I've already tried to use solutions like add +1 to nonce or remove this parameter, but that doesn't help me because transactions are still building with the same nonce. How can that be fixed or what am I doing wrong?
class CoinpaymentsIPNPaymentView(BaseCoinpaymentsIPNView):
def post(self, request, order_id, *args, **kwargs):
status = int(request.POST.get('status'))
order = Order.objects.get(id=order_id)
order.status = request.POST.get("status_text")
if not status >= 100:
order.save()
return JsonResponse({"status": status})
amount = Decimal(request.POST.get('amount1'))
record = Record.objects.create(
user=order.user,
type='i',
amount=amount,
)
order.record = record
order.save()
gold_record = GoldRecord.objects.get(from_record=record)
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=ABI_JSON)
transaction = contract.functions.transfer(order.user.wallet.address, int(gold_record.amount * 10 ** 18)).buildTransaction({
'chainId': 1,
'gas': 70000,
'nonce': w3.eth.getTransactionCount(WALLET_ADDRESS) # address where all tokens are stored
})
signed_tx = w3.eth.account.signTransaction(transaction, WALLET_PRIVATE_KEY) # signing with wallet's above private key
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
print(tx_hash.hex())
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
return JsonResponse({"status": status})
P.S. I've already asked it on Ethereum StackExchange, but nobody answered or commented it: https://ethereum.stackexchange.com/questions/80961/sending-tokens-out-on-coinpayments-success-payment-using-web3py
Ok, let the web know answer and solution that I found out by myself
Each transaction should have unique nonce, so I noticed that if I do a loop for sending transactions and set nonce as w3.eth.getTransactionCount(WALLET_ADDRESS) + index then it sends all transactions without any errors. So I removed instant coins sending (even removed waitForTransactionReceipt to speed up it), and made management command where I process all payouts and if it was sent successfully I assign its tx_hash and run it every 10 minutes with Heroku Scheduler

Tweepy - Get All Followers For Account - Rate Limit Issues

Below is my working code to get twitter followers for certain accounts (#hudsonci in this case).
My issue is the time that it is taking to pull in all of these followers. This account specifically has approx 1,000 followers ... I can only get to 300 at a time with the rate limiting restrictions. So, it is taking > an hour to get all the followers for this account. I can imagine this will become a huge pain in the ass for large accounts.
I am looking for some suggestions for how I can improve this. I feel like I am not taking full advantage of the pagination cursor, but I can't be sure.
any help is appreciated.
#!/usr/bin/env python
# encoding: utf-8
import tweepy
import time
#Twitter API credentials
consumer_key = "mine"
consumer_secret = "mine"
access_key = "mine"
access_secret = "mine"
#authorize twitter, initialize tweepy
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api = tweepy.API(auth)
def handle_errors(cursor):
while True:
try:
yield cursor.next()
except tweepy.TweepError:
time.sleep(20 * 60)
for user in handle_errors(tweepy.Cursor(api.followers,screen_name='hudsonci').items()):
print user.screen_name
As per the Twitter documentation for followers you need to use the count parameter.
Specifies the number of IDs attempt retrieval of, up to a maximum of 5,000 per distinct request.
So, adding count=5000 should help you.
You are getting 300 followers at a time because getting the followers object (as opposed to IDs only) has a page limit 20. With 15 requests per window, that comes out to be 300 followers.
Here are the docs for followers: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list