can anyone explain me this assert condition? - function

i would like to understand this assert condition in function send token.....i think the first assert for before adding tokenbalance is always gather then the up coming token but I don't sure about it....?
pragma solidity ^0.5.11;
contract EventExample {
mapping(address => uint) public tokenBalance;
event TokensSent(address _from, address _to, uint _amount);
constructor() public {
tokenBalance[msg.sender] = 100;
}
function sendToken(address _to, uint _amount) public returns(bool) {
require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
assert(tokenBalance[_to] + _amount >= tokenBalance[_to]);
assert(tokenBalance[msg.sender] - _amount <= tokenBalance[msg.sender])
;
tokenBalance[msg.sender] -= _amount;
tokenBalance[_to] += _amount;
emit TokensSent(msg.sender, _to, _amount);
return true;
}
}

These two assert conditions provide a way to prevent integer overflow and underflow.
The max value of uint256 is 2^256-1, which is approx. 10^77. If you want to add two numbers that would result in a value larger that the max value, it would overflow the integer.
Example with smaller values so it's easier to imagine:
Largest value of uint8 is 255. So if you have a value 250 and you want to add 10, it overflows the max value, and becomes 4 (because 255 + 1 equals 0 in case of uint8).
The same goes the other way around. You have a value 5 and want to subtract 10. Since it's an unsigned integer, there's no negative numbers, and it underflows and becomes 251 (because 5 - 5 is 0, and then the remaining 5 is subtracted from the "max value + 1").
You can find more info about the integer overflow/underflow vulnerability in the SWC registry: https://swcregistry.io/docs/SWC-101

Related

Is this a correct way to calculate price for tokens with different decimals?

I've tested this function on a few different examples and it seems to return proper numbers but I'm not sure if this is correct and will work for all cases (different decimals of A and B, different values of amountOfB and priceForA etc).
Is this the right way to compute price of token A that have fixed price in amount of B tokens?
function calculatePrice(uint8 decimalsA, uint256 priceForA, uint256 amountOfB) public {
return amountOfB * 10 ** decimalsA / priceForA;
}
Decimals for both tokens A and B can be equal or one can be higher or lower than the other.
For example
decimalsA = 6;
decimalsB = 18;
// priceForA is price for 1 (human readable) A token which is 0.01 (human readable) B tokens
// so in other words for 1000000 A you need to pay 10000000000000000 B
priceForA = 10000000000000000;
// this is the amount of B tokens that will be used to buy A tokens
amountOfB = 50000000000000000;
In this example we should get 5000000 as return value so 5A (human readable) tokens.

Gas efficiency of totalSupply() vs. a tokenID counter | ERC-721

I'm creating a solidity contract for an NFT and in my mint function I'm not sure if a call to totalSupply() vs using a token counter and incrementing it is better practice. Does either variation cost more gas? Is one the more standard practice? I've seen examples of both being used.
Variation 1:
contract MyNFT is ERC721Enumerable, PaymentSplitter, Ownable {
using Counters for Counters.Counter;
Counters.Counter private currentTokenId;
...
function mint(uint256 _count)
public payable
{
uint256 tokenId = currentTokenId.current();
require(tokenId < MAX_SUPPLY, "Max supply reached");
for(uint i = 0; i < _count; ++i){
currentTokenId.increment();
uint256 newItemId = currentTokenId.current();
_safeMint(msg.sender, newItemId);
}
}
}
Variation 2:
function mint(uint256 _count)
public payable
{
uint supply = totalSupply();
require( supply + _count <= MAX_SUPPLY, "Exceeds max supply." );
for(uint i = 0; i < _count; ++i){
_safeMint(msg.sender, supply + i);
}
}
Both versions seem to work. I just want to be sure I'm using the most efficient / secure. Thanks for any advice!
First off all, you need to show us the underlying implementations. However, I can speculate that these are unmodified openzeppelin implementations for ERC721Enumerable and Counters.
For your case only, using Counter seems a little bit pointless to me.
It increases your deployment costs(just a little bit) because of redundant code coming from Counter library
You already know the length of your tokens array, why keep it twice? Counters is created for situations where you don't know the number of elements, like a mapping.
I am not guaranteeing correctness of the following analysis
Calling totalSupply (looking from opcode point of view) will:
jump to totalsupply (8 gas)
sload tokens.slot (200) gas
However, while using Counter, you sstore (>= 5000 gas) each time you decrement and sload (200 gas) each time you read.
As long as i am not mistaken about Counter using storage, and therefore sstore and sload opcodes, second variant will use much less gas.

How to random mint a static number of NFT?

I'd like to mint these amount of tokens:
200 super
300 rare
500 common
But the mint process needs to be random, you can get a (super, rare, or common) but at the end of the process, it should be minted the same amount of 200 super, 300 rare, and 500 common.
The following code does the random but the final amount of tokens will be different from the beginning:
function safeMint(address to) public onlyOwner {
require(_tokenIdCounter.current() < totalSupply(), "There's no token to mint.");
require(mintCnt[msg.sender] < maxMintCntPerAddress, "One address can mint 1 tickets.");
if(mintPrice > 0) {
require(mintPrice == msg.value, "Mint price is not correct.");
address payable _to = payable(serviceAddress);
_to.transfer(mintPrice);
}
uint randomNumber = random(expectedTokenSupply - _tokenIdCounter.current());
for (uint256 i = 0; i < _tokenMetadata.length; i++) {
if(_tokenMetadata[i].amount <= randomNumber) {
_safeMint(to, _tokenIdCounter.current());
_setTokenURI(_tokenIdCounter.current(), _tokenMetadata[i].uri);
_tokenIdCounter.increment();
break;
}
}
}
function random(uint maxValue) internal returns (uint) {
return uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, _tokenIdCounter.current()))) % maxValue;
}
First don't use block.timestamp or any block or blockchain data as a source of randomness, because it will cause the "randomness" be predictable or possible to be manipulated by minners, try with chainlink as a source of randomness, they have a good examples in their docs, if you want to have a fixed supply of each type of tokens you can have 3 variables to know how much of each one have been minted, and when you got the random number and all that you need you just need to apply some math, in this case you want the tokens to be 20% of super, 30% of rare and 50% of common, you only have to do the math you need to decide wich one will be minted, and in case of that type has already reach is max supply what will happend?

Sometimes I lose array items in Ethereum smart-contract

I have found strange problem in my smart contract. I use testrpc (v4.1.3) and last MetaMask as local dev environment.
Please, see code below (it is short version, just place with problem):
struct PayRecord {
address sender;
uint256 sum;
uint256 blockNumber;
uint256 status;
}
event PaymentPlaced(address senderAddress, uint256 blockNumber, uint256 payIndex, string guid);
PayRecord[] public payments;
function payForSomething(string guid) payable {
uint256 newLength = payments.push(PayRecord(msg.sender, msg.value, block.number, 0));
PaymentPlaced(msg.sender, block.number, newLength-1, guid);
}
function changeSomething(uint256 paymentIndex) {
if(payments[paymentIndex].status == 0){
payments[paymentIndex].status == 1;
}
}
Often everything works fine:
user calls function payForSomething()
user gets event PaymentPlaced in browser
user calls changeSomething()
but...
SOMETIMES I have next problem:
user calls payForSomething()
user gets event PaymentPlaced (for example: blockNumber = 10, payIndex = 5).
user calls changeSomething() - and gets error "invalid opcode"
if user calls payForSomething() again - he gets event PaymentPlaced with data (blockNumber == 15, payIndex = 5)
The same array length, different block numbers, two insertion events...
So...Sometimes it happens, sometimes everything works fine. I always have only one user, only I works with this smart-contract (I'm still developing it).
Why do I lose items from array?

Smart contract limitations in Ethereum & Fabric

I am trying to make a smart contract to achieve the following automatically. But I stuck in the implementation. How can I run the (2) Tx without having B to sign the Tx, ie: I want it to run automatically once (1) is activated and condition (2) is ready.
Pseudocode(one):
A send 50 to B (1)
if (B > 50) (2)
B send 10 to C (3)
The code above involves multiple owners, ie. A, B and C. Firstly, A actives the contract by running/signing Tx (1). Then the contract checks condition (2). Now but how can run(3) automatically without having to force B to sign?
Ultimately, is the contract able to sign (or proxy sign) on behave of B?
edit
What about below in any chaincode? Can it run automatically, ie without D has to sign using D's private key in (3)?
Pseudocode(two):
A send 50 to B (1)
if (something is true, say Z > 50) (2)
D send 10 to F (3)
Ultimately, is the contract able to sign (or proxy sign) on behave of B?
No.
A starts the transactions by sending necessary funds to the contract, and then the contract disperses funds according to the rules. So, A -> contract, contract -> B and possibly, contract -> C.
Although it's outside the question raised, it will possibly help you avoid refactoring later to observe the best practice of separating the two sends if B and/or C are untrusted contracts. You would just do the accounting in the deposit step, and then use a withdrawal pattern as B & C claim their entitlements (separate transactions).
Hope it helps.
Updated:
Here's a rough outline that might give you some ideas. I wasn't sure if the > 50 was all-time total or a single payment > 50. It's a contrived example that expects you to pass in two valid addresses for B & C so the contract knows their addresses.
You can send amounts from any address (A) and the contract will keep track of owedToB and owedToC.
You should be able to send a transaction to withdraw() from B or C to claim the balance owed.
It's a little time-consuming to set everything up for a full test so just presenting "as is".
pragma solidity ^0.4.6;
contract Royalty {
address public B;
address public C;
uint public owedToB;
uint public owedToC;
event LogPaymentReceived(address sender, uint amount);
event LogPaid(address recipient, uint amount);
// pass in two addresses, B & C for this simple constructor
function Royalty(address addressB, address addressC) {
B = addressB;
C = addressC;
}
function pay()
public
payable
returns(bool success)
{
owedToB += msg.value;
// You can do B.balance > 50 but beware how it drops below 50 after withdrawal
// A little more involved, but you can have totalReceipts AND totalPayments so owedToB is totalReceipts - totalPayments
// It all depends on the business terms you're trying to enforce.
if(msg.value > 50) {
owedToC += 10;
owedToB -= 10;
}
LogPaymentReceived(msg.sender, msg.value);
return true;
}
function withdraw()
public
returns(uint amountSent)
{
if(msg.sender != B && msg.sender != C) throw; // only B & C can withdraw
uint amount;
if(msg.sender == B) {
amount = owedToB;
owedToB = 0;
if(!B.send(amount)) throw;
LogPaid(B,amount);
return amount;
}
if(msg.sender == C) {
amount = owedToC;
owedToC = 0;
if(!C.send(amount)) throw;
LogPaid(C,amount);
return amount;
}
// we shouldn't make it this far
throw;
}
}