BEP-20 smart contract with airdrop feature - cryptocurrency

I'm creating my own BEP20 token and want to implement a function to airdrop tokens to multiple addresses at once to reduce gas fees. Use case would be a giveaway of free tokens to selected users after the launch.
This is the code that I have so far, however there seems to be something missing for it to work properly:
contract Airdrop is Ownable {
IERC20 token;
struct PaymentInfo {
address payable payee;
uint256 amount;
}
constructor(address _token) public {
token = IERC20(_token);
}
function batchPayout(PaymentInfo[] calldata info) external onlyOwner {
for (uint i=0; i < info.length; i++) {
token.transfer(info[i].payee,info[i].amount);
}
}
function transfer(address to, uint256 amount) external onlyOwner {
token.transfer(to, amount);
}
}
Can I use code snippets from ERC20 examples? Will they work with BEP20?

Ethereum and Binance Smart Chain use slightly different token standards, so most of the Solidity code designed for Ethereum virtual machine need minor changes, including replacing mentions of IERC20 with IBEP20 and using the correct Solidity file for IBEP20 interface.
If you use correct version of Solidity compiler, it should tell if the code needs further changes. For real life testing, it's better to test the code on testnet of Binance Smart Chain.

You do not need to include batch send in the token itself. Because smart contracts are composable, there exist third-party smart contracts that can do batch send on behalf of any token.
One example service with open-source smart contracts is Token BulkSender. The source for the bulk send smart contract is here.

Related

Ethers js transferring ERC20 between contracts

I have 2 contracts, first one is openzeppelin ERC20 token and second one is a lottery contract where players can bet on a number.
lottery.sol
pragma solidity ^0.8.4;
import "./Token.sol"; //import ERC20 token
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract Lottery is Ownable {
Token token;
constructor(Token _token) public {
token = _token;
}
// store information about player's bet
struct PlayersStruct {
uint betAmount;
uint betOnNumber;
}
mapping(address => PlayersStruct) public balances;
function enterLottery(string memory _betOnNumber) public payable {
address player = msg.sender;
uint amount = msg.value;
// transfer token from player's wallet to lottery contract
token.transferFrom(player, address(this), betAmount);
balances[player].betAmount += amount ;
balances[player].betOnNumber = _betOnNumber;
}
And this is how I call it from ReactJS
async function stakeBet() {
const amount = ethers.utils.parseEther("10");
const maxAmount = ethers.utils.parseEther("1000000");
// approve token once so player can save on gas in future
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
}
There are 2 problems with this code:
I have to approve the contract every time, even I'm approving maxAmount higher than betting amount. How do I let Metamask know that contract was already approved?
After approving the ERC20 token, the token for transfer is actually ETH and not ERC20 token defined in Token.sol, how do I specify that ERC20 is the one to transfer?
I'm testing on Kovan test net.
In your stakeBet function, you are calling those functions in order:
await token.approve(stakingContract.address, maxAmount);
// bet 10 tokens on number 20
await lottery.enterLottery(20, {value: amount,});
When you call approve, you are actually updating the allowance mapping. Let the contract know that, you are allowing certain amount for the allowed address. It should be implemented like this:
function approve(address _spender, uint _value)public returns (bool success){
// allowance tells how many tokens can be sent
allowance[msg.sender][_spender]=_value;
// This event must trigger when a successful call is made to the approve function.
emit Approval(msg.sender,_spender,_value);
return true;
}
Token transfer or coin transfer is actually updating the state inside the contracts. With the approve function you updated the allowance. Now
token.transferFrom should be implemented like this:
// my address is allowing your address for this much token
mapping(address=>mapping(address=>uint)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success){
// check the allowance
require(_value <=allowance[_from][msg.sender]);
// update the balances
balanceOf[_to]+=_value;
balanceOf[_from]-=_value;
allowance[_from][msg.sender]-=_value;
// emitting an event
emit Transfer(_from,_to,_value);
return true;
}
ETH is not ERC20 token. Instead you have to implement WETH token and transfer WETH token. WETH is wrapped version of eth. https://weth.io/
All Ethereum wallet addresses are ERC20 compatible. Moreover, this means that every ERC20 transfer can happen between two Ethereum wallet addresses, or ERC20-compatible addresses. This typically includes all EVM-compatible blockchains. You send weth token and user can swap in metamask:
For the 1st part, you have done what you intended to do, i.e, you have set the allowance to the maximum amount so that the user doesn't have to pay for calling transaction for allow() each time.
The MetaMask is asking your permission for gas fees (in ETH) for sending "betAmount" amount of tokens to the contract.
I am new to ethereum, but I have faced similar circumstances in my projects. So, this is according to my understanding.
Also, for the 2nd problem, as I said earlier, MetaMask is asking for your permission for paying the gas fees (which it takes in ETH, but actual transfer of tokens must also be taking place. Only, some amount of ETH is spent for the "Gas Fees".
I got a real good article discussing the same thing.
Link: https://medium.com/ethex-market/erc20-approve-allow-explained-88d6de921ce9
You can see the demonstration of what I just said. You can see that the gas fees are taken in ETH. Also, if you had not set the allowance earlier to maximum, you would have to pay gas fees two times for a transaction to your contract to happen, first to call approve() for allowance, then to get the "betAmount" amount of tokens transferred to the contract.

Solidity Contract A Calling Contract B Payable Function

In the simplified (incomplete) code below, the runIt() function in contract B makes a transfer to contract A. This works fine, I can check the balance of contract A afterwards and it receives the funds fine at this stage alone.
Immediately after this transfer, the runIt() function in contract B calls the randomEvent() function in contract A. This function in contract A is meant to make another transfer, sending the entire contract A balance to contract C (not shown). For some reason I can never get this part to work. I tried to simplify the code by changing the target of randomEvent() to a wallet address instead of a contract address but I experience the same problem there. MetaMask flags the transaction as having issues and it won't process if you try.
In this code example it might seem like I'm sending funds in circles but that's just because I've simplified it for ease of explanation. Can anyone please help me figure out how I can execute a second transfer from contract A to contract C, following the receiving of funds from contract B? I initially tried to call the randomEvent() function from contract A directly, inside the payable function so that it fires every time it receives a transfer from anywhere. This would work perfectly fine, too, except I ran into the same issue and error. It didn't work that way, either.
I'm new to Solidity so I'm probably missing something stupid but any advice would be much appreciated. Yes, I know I'm using a very old version of Solidity, I'll eventually refactor it to something more modern.
pragma solidity ^0.4.17;
contract A {
function () public payable {
}
function randomEvent() public payable {
address wallet = 0x0000; // Random Contract C Address
wallet.transfer(address(this).balance);
}
}
}
contract B {
address public platform;
platform = 0x000; // Contract A Address
uint someValue = 1000000; // Irrelevant Example Amount
function runIt() public payable {
platform.transfer(someValue); // This works fine, funds in Contract A are received.
A ContractA = A(platform);
ContractA.randomEvent(); // This transaction fails and won't process, funds aren't moved from Contract A to Contract C.
}
}

How can I log the generated Access Token in Identity Server 4?

I would like to know how we can log the generated Refresh & AccessToken in IdentityServer 4.
Currently, we've got the custom implementation about the JwtAccessToken and we writes it + userId/name to the central logging system whenever it generates a new Access token. For Apis (we've more than 10), it always writes all incoming requests + JwtToken to the same logging system. So, we can easily trace what the user had done and see the logs/values at that particular time.
Now, we are going to replace that custom security implementation with IDSV4 and we couldn't find out a way to log the generated token in IDSV4.
We know that we can get the Access Token in .Net App by using await HttpContext.GetAccessTokenAsync(). But we don't want to manually send a log from all our apps (.Net, Spas, Apis (Client Credentials)) which are going to integrate with IDSV. We want to manage that AccessToken logging in a central place as we did before.
I looked at the IDSV4 sourcecode TokenEndpoint.cs Line120, LogTokens()
if (response.IdentityToken != null)
{
_logger.LogTrace("Identity token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.IdentityToken);
}
if (response.RefreshToken != null)
{
_logger.LogTrace("Refresh token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.RefreshToken);
}
if (response.AccessToken != null)
{
_logger.LogTrace("Access token issued for {clientId} / {subjectId}: {token}", clientId, subjectId, response.AccessToken);
}
Actually, they write the TraceLogs for the actual tokens. But we don't want to update the log level to Trace because it'll flood our logging system.
So, I would like to know whether it's possible to implement a feature to write a generated tokens to a log whenever IDSV4 issues an AccessToken. Is there anyway to intercept these tokens after the generation?
Or do we have to manually log AccessTokens whenever it's generated or refreshed in all our clients?
Update:
Thanks to sellotape for giving me an idea for DI. The following is the correct class to intercept the generated Token:
public class CustomTokenResponseGenerator : TokenResponseGenerator
{
public CustomTokenResponseGenerator(ISystemClock clock, ITokenService tokenService, IRefreshTokenService refreshTokenService, IResourceStore resources, IClientStore clients, ILogger<TokenResponseGenerator> logger) : base(clock, tokenService, refreshTokenService, resources, clients, logger)
{
}
public override async Task<TokenResponse> ProcessAsync(TokenRequestValidationResult request)
{
var result = await base.ProcessAsync(request);
// write custom loggings here
return result;
}
}
After that you can replace default class from IDSV4 with your custom class
services.Replace(ServiceDescriptor.Transient<ITokenResponseGenerator, CustomTokenResponseGenerator>());
There are many places to hook in for this; one is to create your own implementation of ITokenService by deriving from DefaultTokenService.
Override CreateAccessTokenAsync() and have it do:
Token result = await base.CreateAccessTokenAsync(request);
// Your logging goes here...
return result;
Swap in your version in your DI container at Startup (make sure it's after the default one has already been added):
services.Replace<ITokenService, MyTokenService>();
... and you should be ready.
As an aside, you should really log hashes of your tokens and not the tokens themselves. You can still match requests and actions to users based on the hash, but then at least nobody will be able to use the logging data to impersonate any of your users.

Web3 JS Library (& Metamask), Get Token Balance

I want to query the eth balance and all token balances of a public key. So far I managed to load web3 and call the getBalance method.
Now, I want to see the balance for ERC20 tokens which are stored with the same public key? E.g. I want to see the balance of OMG tokens?
So far I found that each token contract address has to be queried:
https://ethereum.stackexchange.com/questions/15372/how-can-i-view-all-the-tokens-and-contracts-associated-with-an-ethereum-address
omgContractAddress = "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
OmgContract = web3.eth.contract(abi)
omgContract = OmgContract.at(omgContractAddress)
someUsersAddress = "0x75087d9faa28d653750f3e4c86e7dcf6aff0a916"
omgContract.balanceOf someUsersAddress, (err, balance)-> #some owner
console.error err
console.info balance.toNumber()
Questions:
1) Do I need the abi of each token? Or can I use a standardized abi for ERC20 tokens as long as I just want to use standardized methods?
2) Where do I find the abi? Or do I need to recompile each contract?
E.g. OMG: https://etherscan.io/token/OmiseGo
I could find the abis of several tokens on https://etherscan.io/address/<token_address>#code so far they have the same method common in their abi. I just copied the method directly into my source code without reading the original abi. E.g.
abi = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}]

Validate AppEngine Endpoints Client IDs while using custom Authenticator

Earlier our client side apps used Google Sign-In.
Now we are moving to custom auth, as we plan on having the user's phone number as the only identity (instead of a Google Account). But after implementing the custom Authenticator, the client IDs are not being checked and I am able to make API calls from anywhere.
When only Google Sign-in was being used at the client side, the client ID was being validated and I was not able to make API calls from any clients other than the ones authorized.
How do I verify the Client IDs while using custom authenticator?
Code for the Api Endpoint
#Api(name = "apiSubscriber",
clientIds = {
Constants.webClientId,
Constants.androidClientId,
Constants.iOSClientId
},
authenticators = {com.google.api.server.spi.auth.EndpointsAuthenticator.class,
CustomAuth.class},
audiences = {Constants.androidAudience},
)
public class ApiSubscriber {
#ApiMethod
public Subscriber getSubscriberData(User user){
if(user!=null){
//fetches subscriber data
}
}
//... Other ApiMethods
}
Code for Custom Authenticator
public class CustomAuth implements Authenticator {
#Override
public User authenticate(HttpServletRequest request) {
String phoneNumber = request.getHeader("phoneNumber");
String token = request.getHeader("Authorization");
if(checkToken(phoneNumber,token)){
return new User(phoneNumber);
}
return null;
}
private boolean checkToken(String phoneNumber, String token){
//Checks if authorization token is valid
}
}
Unfortunately at this time, it does not appear that you can restrict your Endpoints API to a client and not use Google Sign in.
When using Google's oAuth2 authentication some magic voodoo happens (not exactly sure what) and apps get restricted to the ClientId's that you specify.
However, when you stop using that authentication method, I have found (to my dear disappointment), that it does not work anymore.
See my question here where you can read about my tests and some additional things that may give you more information: Authenticating your client to Cloud Endpoints without a Google Account login
I don't sure is it a problem, but you have some bugs in code you provided.
authenticators = {com.google.api.server.spi.auth.EndpointsAuthenticator.class,
CustomAuth.class,
instead of comma must be bracket. Also, imho, you need only CustomAuth class here.
audiences = {Constants.androidAudience},
comma is redundant.
Second. You don't required to use custom Authenticator. You can send token and phone number as concatenated parameter or two parameters to your service method and check it there.

Resources