How to create a transaction using web3 or ethers.js without setting private_key - blockchain

What i am trying to do:
Building a small app that allows a user to purchase a service for a set amount of tokens. For example, 100 tokens for service A, 500 tokens for service B. This will be for a custom token on the harmony blockchain.
What i know:
I already know how to connect to metamask and get the users address. Signer and provider are available to me.
What confuses me:
Examples and documentation all refer to a private_key and creating a wallet, i don't need to do that, i need to use the users existing wallet.
What i need to do:
Prompt a transaction in the user wallet (harmony one or metamask) for a set amount of tokens.
Check if the user has required balance (seems trivial knowing i can read their balance).
Make the transaction. Also seems ok after reading the docs.
Get a receipt, then call a callback/my code. Again, seems ok after reading the docs.
All pretty straight forward, but again - every document i read always refers to setting a private key - surely i don't need to do this?

A transaction always needs to be signed by a private key generating the sender address. Otherwise it's rejected by the network.
Examples and documentation all refer to a private_key and creating a wallet, i don't need to do that, i need to use the users existing wallet.
every document i read always refers to setting a private key - surely i don't need to do this?
A backend approach is to import the private key to the app and use it to sign the transaction.
However, there's also a frontend approach: Send a request to a wallet browser extension to sign the transaction and broadcast it to the network. The wallet extension then pops up a window and lets the user chose whether they want to sign the transaction (with their private key, not shared with the app) and broadcast it - or not.
You can find an example of such request in the MetaMask docs page.
An advantage of this approach is that your app doesn't need to ask for the user's private key. A disadvantage is that if the user haven't installed a browser wallet compatible with your app, they can't send the transaction (or at least not so easily).
Note: I'm not familiar with the Harmony wallet, but I'm assuming it works in a similar way as MetaMask - because Harmony is an EVM-compatible network, and MetaMask only supports EVM-compatible networks.

Related

Get user's wallet address in web3.js

I need to call an API that requires the user's wallet address. However, I can only get wallet's accounts by web3.eth.getAccounts() but not the wallet address.
I am using WalletConnect and was able to create web3 instance.
Thanks!
You need to use requestAccounts and ask the permission from the user to access their wallet addresses.
Due to privacy reasons, the website cannot do this by default.
Also, you need to set up your Web3 properly with the wallet in the order it to work. Because your question did not contain any example code or repeatable example, it is not possible to tell if you are doing it properly.

How to deal with "Only the owner of the contract can update the smart contract"

I am developing a smart contract that holds user information. The problem is that when I try to update the user information from the address that did not deployed the contract, the request is successful but there is no change in the user information. But when I change the user information from the address that deployed the contract it changes the user's information for all the users. Like the change is reflected on all the accounts regardless of the account being different.
function setUserName(string memory _userName) public {
users[msg.sender].userName = _userName;
}
This is my function that updates the user info. I believe that "msg.sender" is the one that is calling the contract and not the one that deployed the contract. I am using metamask and ganache for accounts. The first account is added to metamask in chrome browser and the second account is added to metamask in mozilla firefox.
Steps to reproduce username bug:
Open two different browsers
Start ganache server
In browser one add first address's private key to the metamask in
order to add ETH
In browser two add second address's private key to the metamask in
order to add ETH
Deploy the contracts with " truffle migrate --reset "
It will migrate the contracts with the first address in ganache
From the browser two try to update the username. You will se that
the update was successful but the username was not update (even
after refresh).
Now from browser one update the username by going to the settings
page. You will see that the username is updated and this change is
also reflected on the browser two, regardless of the address being
changed from the browser one's.
Same happens when we try to obtain points by exchanging tokens. From browser one the request is successful but from browser two it throws an error indicating that "ERC20: transfer amount exceeds balance". Even the user has token in their account.
The problem was the data was being saved correctly but when fetching the records solidity was assigning msg.sender to the creator of the contract not the one who sent the transaction. So, in order to deal with this I am sending the user address from frontend in the call function and receiving the address as a parameter in the respective functions. So instead of using the msg.sender I am using the address that I am receiving from frontend.

Verifying a crypto (BSC) address belongs to someone

I am setting up a service where users will pay by sending crypto to a particular address but i need some way to verify that the user is the owner of the address they say they sent it from without it being complicated on the users end.
If I assume the user is using Metamask, there are a variety of signature methods Metamask allows you to do to verify the user owns the address. The specific methods vary, but the basic idea is that it asks the user to sign a message with their private key for the address, and then verifies that the signature is valid. One API for this is described here:
https://medium.com/metamask/scaling-web3-with-signtypeddata-91d6efc8b290
Since Metamask supports BSC and it is generally ETH compatible, I would assume the same functions would work for a BSC address. I'm not familiar enough with every BSC wallet (such as the Trust Wallet) to know if they have similar signing features, they may. In any case, the user's wallet would need to have a feature that allows for this kind of signing for this type of verification to be done--it may not be possible if you are interacting with a user that just has a mobile light wallet with limited features for only sending/receiving.

Stripe identity verification storage

I am reading the documentation regarding stripe verification for managed accounts and I am wondering if it is a good idea to store them as well (as a backup) on a private place where my application has access (like a private bucket on S3 or in a private server)?
I'd recommend against saving any sensitive info on your end such as their SSN, a copy of their government id or their bank account details. The best solution here is to send the details to Stripe directly as they will store it on their end and not log any of it beyond tracking that you provided those info.
You then listen for account.updated events on your Connect webhook endpoint setup in your platform. This will tell you whether Stripe needs more info from that user if fields_needed is set and what delay you have to provide the required details based on verification[due_by].
You can also use properties like legal_entity[ssn_last_4_provided] to know if you've already sent that information to Stripe or if they might need it. This can be found in the docs here

django-tastypie: why are api keys useful and how to support multiple auth schemes?

I'm designing a website in which people will sign on as users and potentially be in multiple groups, which come in a couple of different types. I wanted to both have a website that people can use directly, as well as expose an API that can be consumed by other websites.
What's the best way to implement a login system that works both for regular users of the site itself, as well as which allow API-consuming websites to seamlessly create an account on behalf of the user and allow the user to view their data both from my website and the API-consuming website?
I'm using Django 1.5, so I'm willing to customize the user model and all that. The API will be furnished using Tastypie.
EDIT: Honestly, my main problem is that I don't really understand when API keys are useful and how they coexist (if they do) with regular user logins.
Use case:
The first and use case for API keys is automation. You provide your api key (or commonly called token) to a 3rd party and voila, you can have the 3rd party do stuff for you. When you do not trust the 3rd party anymore, you can just revoke the api key or re-generate it. Api keys allow the user to initiate & authenticate the chain of actions by requesting the token via traditional authentication (e.g username/password), and then the user passes it on to the interested parties. See my little story about phone numbers at the end.
Why not use passwords?
Because you don't want to compromise your users on other websites and have them type their password there in order to use your APIs. If the 3rd party is compromised, then the user's communications or password are compromised.
Here are good resources:
What is token based authentication?
https://developers.google.com/google-apps/sso/saml_reference_implementation
Tastypie APIKey authentication
Django Tastypie: How to Authenticate with API Key
Api keys with tastypie
Here is a good starting point:
from django.contrib.auth.models import User
from django.db import models
from tastypie.models import create_api_key
models.signals.post_save.connect(create_api_key, sender=User)
This should take care of creating api keys thanks to the post_save signal. The second part is to allow more than one scheme for the authentication to fit your use case, so... onto MultiAuthentication:
from django.contrib.auth.models import User
from tastypie.authentication import BasicAuthentication, ApiKeyAuthentication, MultiAuthentication
from tastypie.authorization import DjangoAuthorization
from tastypie.resources import ModelResource
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'auth/user'
excludes = ['email', 'password', 'is_superuser']
authentication = MultiAuthentication(BasicAuthentication(), ApiKeyAuthentication())
authorization = DjangoAuthorization()
Other considerations
These are good practice to never leak sensitive data on the network:
do not do any user/password authentication without ssl or tls.
never use http basic authentication without ssl or tls.
lock down resources users shouldn't access to with permissions.
make sure your responses have correct cache-control headers
always allow users to reset/regenerate/delete their tokens / api keys.
a user need not have only one api key, you can have several of them; one for each 3rd party.
I use gmail so here is an example from https://security.google.com/settings/security (review permissions) where I can see how google openid is used:
Why should you use one api key for each 3rd party? is the same as why should you allow the user to have more than one api key and label them for a particular use?.
The answer is that if the api key is something you share just like your phone number, but you don't need to give the same phone number to all your friends (google voice FTW!).
case 1: one phone number.
If your friend misbehaves and gives it to a bunch of sales rep, you are going to be pretty annoyed. If your phone is the same, then whoever has it may share it with somebody else without your knowing. End results, all sales reps know your number... not so good. But you still want your mom to be able to call you, right? So you can't really change your number. Now imagine a more dangerous situation; you have a tab at the local pizzeria, and they know you by name / phone number. If someone gets your api key, they may impersonate you to order pizza and still charge you (you have a tab!).
case 2: multiple phone numbers:
If you have 100 numbers to you give to 100 different friends, not only can they contact you, but if a sales rep calls you on a particular number, you would know which of your friend gave it away and you can just cut that one number. Mom's now happy because she can tell you where to go for brunch. Your friend now decides to order pizza ... you can now trace it to your friend (or you should provide the pizzeria a number that none of your friend knows).
From a security standpoint there are two main classes of "API Keys" with different purposes for each:
A random API-key that acts sort of like a password and username combined: It is hardwired into client configuration files and is considered a secret. Simply by possessing this key, you have API access. Because the key represents a secret identifying the client (thus validating trust), the secret must be transmitted with every request. The connection must be trusted to ensure the secret is not intercepted, meaning all API access must require TLS/SSL. Often this approach is extended by only using the key on the first request, with the remainder of the connection performed using a rotating session key linked to the client's IP address (much like logging in on a website)
An asymmetric signature scheme: An asymetric cypher like DSA or RSA is used to create a secret key that is stored in the client's configuration. The secret is never shared on the network, and instead encrypts a hash of each API request. The server keeps a public key linked to each private key which decrypts each request's hash signature, and then creates its own hash of the request to validate against. This is the recommended and ideal way to perform API authentication because it does not require TLS/SSL and requires no session management policy.
I am not aware of an API authentication library for django and would recommend looking at the source code of Amazon AWS's HMAC asymmetric signature based approach for an excellent implementation.
I would design the system so that every request needs to have an API key. Ideally you put that in the Authorization header of every request. The API should be as purely RESTFul as possible, ie no session handling. I think thats very important for good API design.
Once that part is done, your users will access the site in exactly the same manor. However, they won't remember their API key, but only their credentials. So, have a login page that authenticates the user based on their credentials, then return the api key to be stored in the client's session. From then on all requests should be authorized with the API key.