How to keep wallet address of an ERC20 token holder private? - token

This is the interface that is required for a token to be an ERC20 token
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
I want to keep private the address of who owns my token. So I deleted the Transfer event and the Approval event. I also made the balanceOf function private.
Is there still some way for a public person to find out who owns one of my tokens? Also is there some way for a public person to know when a trade has taken place?

Is it private?
No
Is there still some way for a public person to find out who owns one of my tokens? Also is there some way for a public person to know when a trade has taken place?
The storage of the contract can be inspected, and the transaction data can be inspected. This data is necessarily public. The best you can do is make it harder for your median user to find this information (although the people who know what they're doing could dig it out and then publish it).
Is it an ERC20 token?
No
This is the interface that is required for a token to be an ERC20 token... I deleted the Transfer event and the Approval event. I also made the balanceOf function private.
Note that deleting those things makes it not an ERC20 token anymore. Those are required in the ERC20 spec.
What now?
Transactions that are private on a public blockchain is an ongoing area of research. If you really want to implement this, it will take diving into the current research in the space, getting familiar with things like ZK-SNARKS and alternatives.

Yes, one of the major features of Bitcoin and Ethereum are that they are public. When anyone uses your smart contract, all their actions are recorded, necessarily and by design, in the blockchain.
See this tx which called a smart contract method. Notice how I can see who sent what to whom, what function was called, and with what parameters.

Related

Can any ERC20 initial supply have 0?

I am creating an ERC20 token. Can I make initial supply 0? If yes than how will increase supply later on?
I just wanna know that can I make initial supply 0 while deploying an ERC20 token?
Yes, you can create an ERC20 token with 0 initial supply by not minting any tokens in the constructor.
Example code with the OpenZeppelin ERC20 implementation. Mind that this code is simplified and not suitable for production as it allows minting new tokens by anyone.
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
// no token minting in constructor => initial supply is 0
}
// you can call this function later to increase the total supply
function mint(uint256 amount) external {
_mint(msg.sender, amount);
}
}

How to handle user OIDC tokens in Blazor Server when the browser is refreshed and the cookie’s tokens are invalid?

Microsoft recommend against using HttpContext in Blazor Server (here). To work around the issue of how to pass user tokens to a Blazor Server app, Microsoft recommend storing the tokens in a Scoped service (here). Jon McGuire’s blog suggests a similar approach that stores the tokens in Cache (here).
Microsoft’s approach above works just fine as long as the user stays within the same Blazor Server connection. However if the access_token is refreshed and the user then reloads the page either by pressing F5 or by pasting a URL into the address bar, then an attempt is made to retrieve the tokens from the cookie. By this time, the access_token and refresh_token in the cookie are no longer valid. Jon McGuire mentions this problem at the end of his blog post and refers to it as Stale Cookies (here). He gives hints about a possible solution, but is very light on implementation instructions. There are many comments at the bottom of that post from people unable to implement a solution, with no apparent working solution suggested. I spent a lot of time searching for a solution and all I found were people asking for one and not receiving any answers that worked.
Having found a solution that seems to work well, and also seems fairly principled, I thought it might be worth sharing my solution here. I would welcome any constructive criticism or suggestions for any significant improvements.
Edit 20220715: After some feedback on our approach from Dominic Baier we removed our Scoped UserSubProvider service in favour of using AuthenticationStateProvider instead. This has simplified our approach. I have edited the following answer to reflect this change.
This approach combines advice from Microsoft on how to pass tokens to a Blazor Server app (here), with server side storage of tokens in a Singleton service for all users (inspired by Dominick Baier’s Blazor Server sample project on GitHub here).
Instead of capturing the tokens in the _Host.cshtml file and storing them in a Scoped service (like Microsoft do in their example), we use the OnTokenValidated event in a similar way to Dominick Baier’s sample, storing the tokens in a Singleton service that holds tokens for all Users, we call this service ServerSideTokenStore.
When we use our HttpClient to call an API and it needs an access_token (or refresh_token), then it retrieves the User’s sub from an injected AuthenticationStateProvider, uses it to call ServerSideTokenStore.GetTokensAsync(), which returns a UserTokenProvider (similar to Microsoft’s TokenProvider) containing the tokens. If the HttpClient needs to refresh the tokens then it populates a UserTokenProvider and saves it by calling ServerSideTokenStore.SetTokensAsync().
Another issue we had was if a separate instance of the web browser is open while the app restarts (and therefore loses the data held in ServerSideTokenStore) the user would still be authenticated using the cookie, but we’ve lost the access_token and refresh_token. This could happen in production if the application is restarted, but happens a lot more frequently in a dev environment. We work around this by handling OnValidatePrincipal and calling RejectPrincipal() if we cannot get a suitable access_token. This forces a round trip to IdentityServer which provides a new access_token and refresh_token. This approach came from this stack overflow thread.
(For clarity/focus, some of the code that follows excludes some standard error handling, logging, etc.)
Getting the User sub claim from AuthenticationStateProvider
Our HttpClient gets the user's sub claim from an injected AuthenticationStateProvider. It uses the userSub string when calling ServerSideTokenStore.GetTokensAsync() and ServerSideTokenStore.SetTokensAsync().
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
string userSub = state.User.FindFirst("sub")?.Value;
UserTokenProvider
public class UserTokenProvider
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public DateTimeOffset Expiration { get; set; }
}
ServerSideTokenStore
public class ServerSideTokenStore
{
private readonly ConcurrentDictionary<string, UserTokenProvider> UserTokenProviders = new();
public Task ClearTokensAsync(string userSub)
{
UserTokenProviders.TryRemove(userSub, out _);
return Task.CompletedTask;
}
public Task<UserTokenProvider> GetTokensAsync(string userSub)
{
UserTokenProviders.TryGetValue(userSub, out var value);
return Task.FromResult(value);
}
public Task StoreTokensAsync(string userSub, UserTokenProvider userTokenProvider)
{
UserTokenProviders[userSub] = userTokenProvider;
Return Task.CompletedTask;
}
}
Startup.cs ConfigureServices (or equivalent location if using .NET 6 / whatever)
public void ConfigureServices(IServiceCollection services)
{
// …
services.AddAuthentication(…)
.AddCookie(“Cookies”, options =>
{
// …
options.Events.OnValidatePrincipal = async context =>
{
if (context.Principal.Identity.IsAuthenticated)
{
// get user sub
var userSub = context.Principal.FindFirst(“sub”).Value;
// get user's tokens from server side token store
var tokenStore =
context.HttpContext.RequestServices.GetRequiredService<IServerSideTokenStore>();
var tokens = await tokenStore.GetTokenAsync(userSub);
if (tokens?.AccessToken == null
|| tokens?.Expiration == null
|| tokens?.RefreshToken == null)
{
// if we lack either an access or refresh token,
// then reject the Principal (forcing a round trip to the id server)
context.RejectPrincipal();
return;
}
// if the access token has expired, attempt to refresh it
if (tokens.Expiration < DateTimeOffset.UtcNow)
{
// we have a custom API client that takes care of refreshing our tokens
// and storing them in ServerSideTokenStore, we call that here
// …
// check the tokens have been updated
var newTokens = await tokenStore.GetTokenAsync(userSubProvider.UserSub);
if (newTokens?.AccessToken == null
|| newTokens?.Expiration == null
|| newTokens.Expiration < DateTimeOffset.UtcNow)
{
// if we lack an access token or it was not successfully renewed,
// then reject the Principal (forcing a round trip to the id server)
context.RejectPrincipal();
return;
}
}
}
}
}
.AddOpenIdConnect(“oidc”, options =>
{
// …
options.Events.OnTokenValidated = async n =>
{
var svc = n.HttpContext.RequestServices.GetRequiredService<IServerSideTokenStore>();
var culture = new CultureInfo(“EN”) ;
var exp = DateTimeOffset
.UtcNow
.AddSeconds(double.Parse(n.TokenEndpointResponse !.ExpiresIn, culture));
var userTokenProvider = new UserTokenProvider()
{
AcessToken = n.TokenEndpointResponse.AccessToken,
Expiration = exp,
RefreshToken = n.TokenEndpointResponse.RefreshToken
}
await svc.StoreTokensAsync(n.Principal.FindFirst(“sub”).Value, userTokenProvider);
};
// …
});
// …
}

How can accept other token in my Smart Contract?

The token is ERC721 by OpenZeppelin
I'm trying to add USDC payments to my Smart Contract, but I'm having problems.
This is my function to accept token.. but transfer its called by Smart Contract. Dont work...
function AcceptPayment(uint32 amount) public {
tokenUSDC.transfer(address(this), amount * priceCapsule);
bulkMint(_msgSender(), amount);
}
Allowance and approve its working fine, testing with Remix.
New try.. but get: Execution reverted on Remix
function AcceptPayment(uint32 amount) public {
bool success = tokenUSDC.transferFrom(msg.sender, address(this), amount * priceCapsule);
require(success, "Could not transfer token. Missing approval?");
bulkMint(_msgSender(), amount);
}
I can't find a solution to make the transfer from the Smart Contract itself.
The user needs to approve() your contract address to pull their tokens. This action needs to be called directly from the user address (on the token contract).
Then you can transferFrom() their address to yours.
function AcceptPayment(uint32 amount) public {
bool success = tokenUSDC.transferFrom(msg.sender, address(this), amount * priceCapsule);
require(success, "Could not transfer token. Missing approval?");
bulkMint(_msgSender(), amount);
}

How to enable Claim Tokens in Solidity Smart Contract?

I am currently using the Open Zapeline smart contract for my Dapp, I wanted to know if there is a way where users can claim my tokens (i.e transfer from owner wallet to current user) I know a method with hardcoding the private keys but is there any way wherein the Smart Contract I can set msg.Sender as Owner or Transfer tokens from Owner account to the user without any signatures?
You can use the internal function _transfer() (GitHub link) that only validates is the from param is the actual owner of the token. But it doesn't validate if the msg.sender is the token owner.
Note that this function has internal visibility, so it's only executable from inside of your contract.
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract MyCollection is ERC721, Ownable {
constructor() ERC721("MyCollection", "MyC") {
_mint(owner(), 1);
}
function claim() external {
require(ownerOf(1) == owner(), "Already claimed");
_transfer(owner(), msg.sender, 1);
}
}

SafeMath error on sending tokens via contract

While attempting to send tokens via a contract I run in to the error message: "SafeMath: subtraction overflow."
Initially I only used the transfer functionality. However, as I thought the msg.sender only has to send its tokens to the other user (via truffle console this is no issue). However, reading [this] I got the impression it is actually the contract address that becomes the msg.sender in the TokenContract. Therefore, (as only the accounts but not the contract itself) I thought that I have to send tokens to the contract first, subsequently approve that the contract is allowed to send tokens on behalf of the msg.sender and subsequently transfer the money. However, I keep having the SafeMath error.
The TokenContract (not the interface below) implements the The most simple version of my code is as follows:
contract ContractA {
function pay () public returns (bool) {
TokenContract tk = TokenContract("tokenContractAddress");
tk.transferFrom(msg.sender, address(this), 5);
tk.approve(address(this), 5);
tk.transfer("someAccount", 5);
return true;
}
}
interface TokenContract {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
}
contract TokenContract is ERC20, ERC20Detailed {
constructor() ERC20Detailed("Token", "TKN", 18) public {
_mint(msg.sender, 1000);
}
}
Obviously I expect not the safeMath error to appear. As I transfer money and approve. I just expect the same behaviour as when using truffle console.
I assume that the address calling ContractA hasn't set an allowance for the contract.
Requirements:
* the caller must have allowance for sender's tokens of at least amount.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.3.0/contracts/token/ERC20/ERC20.sol
/**
* #dev See `IERC20.transferFrom`.
*
* Emits an `Approval` event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of `ERC20`;
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `value`.
* - the caller must have allowance for `sender`'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
return true;
}
Caller of Contract A approves an allowance for the Token
Caller of Contract A calls pay function and which calls transferFrom to transfer from the user to the recipient within the previously set allowance.
If you are creating ERC20 tokens you may want to look at the OpenZeppelin Contracts implementation to see if this meets your needs. See the documentation for details: https://docs.openzeppelin.com/contracts/2.x/tokens#ERC20
If you are transferring a variety of ERC20 tokens you may want to consider using SafeERC20 wrapper to make these calls: https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#SafeERC20
If you need an interface for ERC20 you may want to look at using IERC20: https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20
Alternatively to ERC20 you could look at creating ERC777 tokens (no need to do approve and transferFrom in two separate transactions). See the documentation for details: https://docs.openzeppelin.com/contracts/2.x/tokens#ERC777
If you have questions on using OpenZeppelin you can ask in the Community Forum: https://forum.openzeppelin.com/
Disclosure: I am the Community Manager at OpenZeppelin

Resources