Payable amount can be changed - ethereum

quick question to you. Is it possible to hide "Payable amount" from smart contract? as people can mint from smart contract and set whatever value they want. Screenshot added from Polygonscan. Anyone can enter any amount and it will allow to mint.
Thanks in advance!
[1]: https://i.stack.imgur.com/wQ8J4.png
function mint(uint256 _mintAmount) public payable {
require(!paused, "the contract is paused");
uint256 supply = totalSupply();
require(_mintAmount > 0, "need to mint at least 1 NFT");
require(_mintAmount <= maxMintAmount, "max mint amount per session exceeded");
require(supply + _mintAmount <= maxSupply, "max NFT limit exceeded");
if (msg.sender != owner()) {
if(onlyWhitelisted == true) {
require(isWhitelisted(msg.sender), "user is not whitelisted");
uint256 ownerMintedCount = addressMintedBalance[msg.sender];
require(ownerMintedCount + _mintAmount <= nftPerAddressLimit, "max NFT per address exceeded");
}
require(msg.value >= cost * _mintAmount, "insufficient funds");
}
for (uint256 i = 1; i <= _mintAmount; i++) {
addressMintedBalance[msg.sender]++;
_safeMint(msg.sender, supply + i);
}
}

Polygonscan and other blockchain explorers show the payableAmount field for all Solidity functions with the payable modifier.
However, you can validate the received value in the contract and revert the transaction is the value is unexpected.
function mint() public payable {
require(msg.value == 1e18);
}
Note: msg.value is a read-only global variable returning the amount of received wei. So "1e18 wei" is "1 MATIC" (on Polygon).

Related

How does front runners/sandwich bots avoid "tax" on memecoins?

If an ERC-20 token have "tax" on uniswap transaction hardcoded into them. How does they avoid the deduction of tokens while front running.
transfer logic is as follow:
function _transfer(address from, address to, uint256 amount) private {
require(amount > 0, "Transfer amount must be greater than zero");
require(balanceOf(from) >= amount,"Balance less then transfer");
tax = 0;
uint256 contractETHBalance = address(this).balance;
if(contractETHBalance > 1 ether) {
sendETHToFee(address(this).balance);
}
if (!(_isExcludedFromFee[from] || _isExcludedFromFee[to]) ) {
if(from == uniswapV2Pair){
tax = buyTax;
}
else if(to == uniswapV2Pair){
tax = sellTax;
uint256 contractTokenBalance = balanceOf(address(this));
if(!inSwap){
if(contractTokenBalance > sThreshold){
swapTokensForEth(contractTokenBalance);
}
}
}
}
_tokenTransfer(from,to,amount);
}
function _tokenTransfer(address sender, address recipient, uint256 amount) private {
uint256 stContract = amount*tax/100;
uint256 remainingAmount = amount - stContract;
balance[sender] = balance[sender].sub(amount);
balance[recipient] = balance[recipient].add(remainingAmount);
balance[address(this)] = balance[address(this)].add(stContract);
emit Transfer(sender, recipient, remainingAmount);
}
The address is false in "_isExcludedFromFee" array. As a front running bot it bought and sold in the same block with just one transaction in between.
I tried to think of some explanation but sadly couldn't come up with any. Is it anything to do with being on same block? But if that's so should the logic of "_tokentransfer" deduct tokens no matter the case?
amount is getting subbed no matter the path it takes.

Large amount of wei not being processed by Solidity on Remix

U am trying to implement liquidity pools with Solidity, and had written two functions : addLiquidity() and withdraw() for it. However, the withdraw function doesn't seem to work with Remix when I try to withdraw large sums (like 0.001 ether), but works with sums like 150000 wei or something.
It doesn't seem to be an issue with Remix's IDE (i read somehere it has a problem working with large numbers), because even when I pass the 149999998499999985165 wei in double quotes (e.g. "149999998499999985165") the same error appears.
The error states: "Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted { "originalError": { "code": 3, "data": "0x4e487b710000000000000000000000000000000000000000000000000000000000000011", "message": "execution reverted" } }"
Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface linkStandardToken {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) ;
function balanceOf(address _owner) external returns (uint256) ;
function transfer(address to, uint tokens) external returns (bool success);
}
contract Uniswap
{
using SafeMath for uint256;
uint public totalLiquidity;
uint public balance;
address public owner;
address public tokenAddress = 0xaFF4481D10270F50f203E0763e2597776068CBc5; // REPLACE WITH ACTUAL TOKEN
linkStandardToken token;
bool public poolInit = false;
uint public protocolFees = 30; //in basis points i.e. divide by 10,000
uint public tempTokenPrice = 0;
mapping(address => uint) public liquidityBalances;
constructor()
{
owner = msg.sender;
token = linkStandardToken(tokenAddress);
}
function init(uint _tokenAmount) public payable
{
require(totalLiquidity == 0, "Already initialized");
require(_tokenAmount > 0, "Token amount must be > 0");
require(msg.value > 0, "Eth amount must be > 0");
totalLiquidity = totalLiquidity.add(_tokenAmount);
balance = balance.add(msg.value);
poolInit = true;
require(token.transferFrom(msg.sender, address(this), _tokenAmount), "Can't transfer tokens to contract");
setTokenToEthPrice();
}
fallback() payable external{}
receive() payable external{}
// _amount - input token amount, X - input token reserve, Y- output token reserve
function _swap(uint _amount, uint X , uint Y) public view returns (uint)
{
// code omitted
}
function swapEthToToken(/*uint _inputEthAmount*/) public payable
{
// code omitted
}
function swapTokenToEth(uint _tokenAmount) public payable
{
// code omitted
}
function setTokenToEthPrice() public // set to internal later
{
tempTokenPrice = _swap(1, balance , token.balanceOf(address(this))) ;
}
function addLiquidity(uint maxTokens) payable public returns (uint)
{
require(msg.value > 0, "msg.val <= 0");
require(totalLiquidity > 0, "totalLiquidity <= 0");
uint tokensBalance = getTokenBalance(address(this));
uint tokensToAdd = msg.value.mul(tokensBalance)/balance;
require(tokensToAdd <= maxTokens , "tokensToAdd > maxTokens");
balance= balance.add(msg.value);
uint mintedLiquidity = msg.value.mul(totalLiquidity)/balance;
liquidityBalances[msg.sender] = liquidityBalances[msg.sender].add(mintedLiquidity);
totalLiquidity = totalLiquidity.add(mintedLiquidity);
require(linkStandardToken(
0xaFF4481D10270F50f203E0763e2597776068CBc5)
.transferFrom(msg.sender, address(this), tokensToAdd));
return mintedLiquidity;
}
function withdraw9(uint256 amount, uint minimumEth, uint minimumTokens) public
{
require(liquidityBalances[msg.sender] >= amount, "Liquidity Balance of msg send < amount");
require(totalLiquidity > 0, "totalLiquidity <= 0");
uint tokenBalance = getTokenBalance(address(this));
uint temp = amount.mul(totalLiquidity);
uint etherToTransfer = temp.div(balance);
uint temp1 = amount.mul(totalLiquidity);
uint tokensToTransfer = temp1.div(tokenBalance);
require(minimumEth < etherToTransfer, "minimumEth >= etherToTransfer");
require(minimumTokens < tokensToTransfer, "minimumTokens >= tokensToTransfer");
balance = balance - etherToTransfer;
totalLiquidity = totalLiquidity.sub(amount);
liquidityBalances[msg.sender] = liquidityBalances[msg.sender].sub(amount);
address payable addr = payable(msg.sender);
addr.transfer(etherToTransfer);
require(linkStandardToken(
0xaFF4481D10270F50f203E0763e2597776068CBc5)
.transfer(msg.sender, tokensToTransfer), "Token transfer unsuccesful");
}
}
library SafeMath {
....// code emitted for compactness
}
As i can see in the last line of widthdraw9 function you use .transfer in order to send ether to some contract. I guess this contract have some code in receive function, so .transfer is not your choose. This function has a gas limitation and any code in receive can break it. If i correctly saw the problem then you should use .call function with enough amount of gas. More about these functions.
The "Gas estimation errored" message doesn't necessarily mean that the problem is with the amount of gas given, just that it hit some error while estimating the amount of gas needed.
The originalError.data has "0x4e487b71...". Looking up those high order 4 bytes on 4byte.directory shows that it's the signature for Panic(uint256), and the code in the low order bytes is "...00011" so the error code is 0x11 (17 decimal). The Solidity doc lists these codes, indicating:
0x11: If an arithmetic operation results in underflow or overflow outside of an unchecked { ... } block.
In the code, balance is not declared in uint etherToTransfer = temp.div(balance). If it's a state variable, could it be 0? Or is there a missing uint256 balance = liquidityBalances[msg.sender]?

How to check how much ERC20 token is being sent in a smart contract call

I've got this piece of code:
function mint(uint amount) public payable {
require(amount <= 10, "token: max of 10 token per mint");
require(_openMint == true, "token: minting is closed");
require(msg.value == _price*amount, "token: must send correct price");
require(_tokenIdTracker.current() + amount <= _max, "token: not enough token left to be mint amount");
for(uint i = 0; i < amount; i++) {
_mint(msg.sender, _tokenIdTracker.current());
_tokenIdTracker.increment();
}
IERC20("0x0789fF5bA37f72ABC4D561D00648ac0000970000").safeTransferFrom(msg.sender, owner(), amount);
}
It mints an ERC721 token with payment in another ERC20 token, and i need to know how muchy ERC20 is being sent. Is there any way to do this?
if you want to know the token amount sent on every transaction, you only have to go on etherscan, search for the contract address, and click the transaction hash of "mint"
if you want to know all amount that was sent, you have to use some tools like thegraph.com

Reusable smart contract

I'm currently trying to develop a simple smart contract
Being relatively new to this, can multiple pairs of users interact with the contract at the same time and benefit from the escrow (will it instantiate a new version for every pair) ?
It's essentially an escrow contract that will hold the funds from a transaction until both the buyer and the seller have accepted the release. Additionally, if the either one of them does not accept the funds will be withheld by the smart contract for a duration of 30 days.
Also, how can I add the address that initially deployed the smart and transfer 3% of the total deposit to that address if the transaction was successful ?
This is what I have tried for now:
pragma solidity 0.7.0;
contract NewEscrow {
enum State {AWAITING_FUNDS,AWAITING_CLAIM,CLAIM,COMPLETE}
State public currentState;
address payable public buyer;
address payable public seller;
address payable public owner;
uint256 public agreementDay;
mapping (address => uint256) deposits;
// checks if msg.sender is equal to buyer
modifier onlyBuyer (){
require(msg.sender == buyer);
_;
}
// checks if msg.sender is equal to seller
modifier onlySeller(){
require(msg.sender == seller);
_;
}
constructor (){
owner = msg.sender;
}
function setVariables (address payable _buyer, address payable _seller, uint256 _agreementDay) public {
buyer = _buyer;
seller = _seller;
agreementDay = _agreementDay + 30 days;
currentState = State.AWAITING_FUNDS;
}
function deposit() public onlyBuyer payable {
require(currentState == State.AWAITING_FUNDS);
uint256 amount = msg.value;
deposits[seller] = deposits[seller] + amount;
currentState = State.AWAITING_CLAIM;
}
function claim () public onlySeller {
require(currentState == State.AWAITING_CLAIM);
currentState = State.CLAIM;
}
function confirm () public onlyBuyer {
uint256 payment = deposits[seller];
deposits[seller] = 0;
seller.transfer(payment);
currentState = State.COMPLETE;
}
function cancelPayement () public onlySeller {
uint256 payment = deposits[seller];
deposits[seller] = 0;
buyer.transfer(payment);
currentState = State.COMPLETE;
}
function release() public{
// funds cannot be retrieved before release day
require (agreementDay < block.timestamp);
uint256 payment = deposits[seller];
deposits[seller] = 0;
buyer.transfer(payment);
revert('funds returned');
}
}
can multiple pairs of users interact with the contract at the same time and benefit from the escrow
Currently not. Only the first pair of users would be able to use it, as currently buyer and seller variables can only hold one value each.
If you want to scale for multiple pairs, you need to make an array of structs representing the buyer and seller connection. From the top of my head, it would look like:
struct Pair {
address buyer;
address seller;
}
Pair[] pairs;
Or another approach, where a common index of the arrays shows that the buyer and seller are connected.
address[] buyers;
address[] sellers;
This scaling would also mean expanding most of the current logic to validate whether the input buyer and seller are connected.
if the either one of them does not accept the funds will be withheld by the smart contract for a duration of 30 days
You'll need to create a new function that checks whether the deposit has been withdrawn and whether it's (deposit date + 30 days) and some validation who can actually withdraw this money.
address constant contractOwner = '0x123'
function withdrawOwner() external {
require(msg.sender == contractOwner); // validate who can withdraw
require(agreementDay + 30 days <= block.timestamp); // check if 30 days has passed since the deposit date
require(deposits[seller] > 0); // check that it hasn't been withdrawn
uint256 amount = deposits[seller]; // make sure the contract is not vulnerable to reentrancy
deposits[seller] = 0;
payable(contractOwner).transfer(amount); // withdraw the money
}
how can I add the address that initially deployed the smart and transfer 3% of the total deposit
Let's expand the 2nd point and use the contractOwner. You'll need to update the deposit function:
function deposit() public onlyBuyer payable {
require(currentState == State.AWAITING_FUNDS);
uint256 amount = msg.value;
// these lines calculate the fee, update the amount and send the fee to the contract owner
// make sure you're not vulnerable to overflow
uint256 fee = (amount / 100) * 3;
payable(contractOwner).transfer(fee); // transfer 3% to the contract owner
amount -= fee; // substract the fee from the amount that is going to be saved
deposits[seller] = deposits[seller] + amount;
currentState = State.AWAITING_CLAIM;
}
Make sure you're not vulnerable to integer overflow. Imagine a scenario:
Buyer deposits 1 wei
Fee is calculated as 3 wei
The contract has enough ETH so it sends the 3 wei to the owner
But the 3 wei is substracted from the 1 in amount so that results in 2^256 - 3 instead of -2
Solidity 0.8+ reverts the transaction automatically if underflow/overflow would happen. If you're using older version of Solidity, you can use for example OpenZeppelin's SafeMath library.

Transfer ERC20 token with Oraclize and Metamask

I'm a beginner and I've been exploring ERC20 tokens. Since a couple of days I have been looking for a solution to this, but in vain.
The problem is the following. I am creating a contract, conforming to the ERC20 protocol. I want to add an extra functionality in the form of an oracle query.
I.e., I want to use a service like "Oraclize", to fetch some external data, return the result.
Depending on the result I would like to transfer some tokens or not.
1) The example token contract I've been working with is the following. It s the contract from CryptoPunks
(https://github.com/larvalabs/cryptopunks/blob/master/contracts/CryptoPunksMarket.sol):
pragma solidity ^0.4.18;
contract CryptoTokensMarket {
address owner;
string public standard = 'CryptoTokens';
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
uint public nextTokenIndexToAssign = 0;
bool public allTokensAssigned = false;
uint public tokensRemainingToAssign = 0;
//mapping (address => uint) public addressToTokenIndex;
mapping (uint => address) public tokenIndexToAddress;
/* This creates an array with all balances */
mapping (address => uint256) public balanceOf;
struct Offer {
bool isForSale;
uint tokenIndex;
address seller;
uint minValue; // in ether
address onlySellTo; // specify to sell only to a specific person
}
struct Bid {
bool hasBid;
uint tokenIndex;
address bidder;
uint value;
}
// A record of tokens that are offered for sale at a specific minimum value, and perhaps to a specific person
mapping (uint => Offer) public tokensOfferedForSale;
// A record of the highest token bid
mapping (uint => Bid) public tokenBids;
mapping (address => uint) public pendingWithdrawals;
event Assign(address indexed to, uint256 tokenIndex);
event Transfer(address indexed from, address indexed to, uint256 value);
event TokenTransfer(address indexed from, address indexed to, uint256 tokenIndex);
event TokenOffered(uint indexed tokenIndex, uint minValue, address indexed toAddress);
event TokenBidEntered(uint indexed tokenIndex, uint value, address indexed fromAddress);
event TokenBidWithdrawn(uint indexed tokenIndex, uint value, address indexed fromAddress);
event TokenBought(uint indexed tokenIndex, uint value, address indexed fromAddress, address indexed toAddress);
event TokenNoLongerForSale(uint indexed tokenIndex);
/* Initializes contract with initial supply tokens to the creator of the contract */
function CryptoTokensMarket() payable {
// balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
owner = msg.sender;
totalSupply = 10000; // Update total supply
tokensRemainingToAssign = totalSupply;
name = "CRYPTOTokenS"; // Set the name for display purposes
symbol = "Ͼ"; // Set the symbol for display purposes
decimals = 0; // Amount of decimals for display purposes
}
function setInitialOwner(address to, uint tokenIndex) {
if (msg.sender != owner) revert();
if (allTokensAssigned) revert();
if (tokenIndex >= 10000) revert();
if (tokenIndexToAddress[tokenIndex] != to) {
if (tokenIndexToAddress[tokenIndex] != 0x0) {
balanceOf[tokenIndexToAddress[tokenIndex]]--;
} else {
tokensRemainingToAssign--;
}
tokenIndexToAddress[tokenIndex] = to;
balanceOf[to]++;
Assign(to, tokenIndex);
}
}
function setInitialOwners(address[] addresses, uint[] indices) {
if (msg.sender != owner) revert();
uint n = addresses.length;
for (uint i = 0; i < n; i++) {
setInitialOwner(addresses[i], indices[i]);
}
}
function allInitialOwnersAssigned() {
if (msg.sender != owner) revert();
allTokensAssigned = true;
}
function getToken(uint tokenIndex) {
if (!allTokensAssigned) revert();
if (tokensRemainingToAssign == 0) revert();
if (tokenIndexToAddress[tokenIndex] != 0x0) revert();
if (tokenIndex >= 10000) revert();
tokenIndexToAddress[tokenIndex] = msg.sender;
balanceOf[msg.sender]++;
tokensRemainingToAssign--;
Assign(msg.sender, tokenIndex);
}
// Transfer ownership of a token to another user without requiring payment
function transferToken(address to, uint tokenIndex) payable {
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] != msg.sender) revert();
if (tokenIndex >= 10000) revert();
if (tokensOfferedForSale[tokenIndex].isForSale) {
tokenNoLongerForSale(tokenIndex);
}
tokenIndexToAddress[tokenIndex] = to;
balanceOf[msg.sender]--;
balanceOf[to]++;
Transfer(msg.sender, to, 1);
TokenTransfer(msg.sender, to, tokenIndex);
// Check for the case where there is a bid from the new owner and refund it.
// Any other bid can stay in place.
Bid bid = tokenBids[tokenIndex];
if (bid.bidder == to) {
// Kill bid and refund value
pendingWithdrawals[to] += bid.value;
tokenBids[tokenIndex] = Bid(false, tokenIndex, 0x0, 0);
}
}
function tokenNoLongerForSale(uint tokenIndex) {
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] != msg.sender) revert();
if (tokenIndex >= 10000) revert();
tokensOfferedForSale[tokenIndex] = Offer(false, tokenIndex, msg.sender, 0, 0x0);
TokenNoLongerForSale(tokenIndex);
}
function offerTokenForSale(uint tokenIndex, uint minSalePriceInWei) {
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] != msg.sender) revert();
if (tokenIndex >= 10000) revert();
tokensOfferedForSale[tokenIndex] = Offer(true, tokenIndex, msg.sender, minSalePriceInWei, 0x0);
TokenOffered(tokenIndex, minSalePriceInWei, 0x0);
}
function offerTokenForSaleToAddress(uint tokenIndex, uint minSalePriceInWei, address toAddress) {
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] != msg.sender) revert();
if (tokenIndex >= 10000) revert();
tokensOfferedForSale[tokenIndex] = Offer(true, tokenIndex, msg.sender, minSalePriceInWei, toAddress);
TokenOffered(tokenIndex, minSalePriceInWei, toAddress);
}
function buyToken(uint tokenIndex) payable {
if (!allTokensAssigned) revert();
Offer offer = tokensOfferedForSale[tokenIndex];
if (tokenIndex >= 10000) revert();
if (!offer.isForSale) revert(); // token not actually for sale
if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) revert(); // token not supposed to be sold to this user
if (msg.value < offer.minValue) revert(); // Didn't send enough ETH
if (offer.seller != tokenIndexToAddress[tokenIndex]) revert(); // Seller no longer owner of token
address seller = offer.seller;
tokenIndexToAddress[tokenIndex] = msg.sender;
balanceOf[seller]--;
balanceOf[msg.sender]++;
Transfer(seller, msg.sender, 1);
tokenNoLongerForSale(tokenIndex);
pendingWithdrawals[seller] += msg.value;
TokenBought(tokenIndex, msg.value, seller, msg.sender);
// Check for the case where there is a bid from the new owner and refund it.
// Any other bid can stay in place.
Bid bid = tokenBids[tokenIndex];
if (bid.bidder == msg.sender) {
// Kill bid and refund value
pendingWithdrawals[msg.sender] += bid.value;
tokenBids[tokenIndex] = Bid(false, tokenIndex, 0x0, 0);
}
}
function withdraw() payable {
if (!allTokensAssigned) revert();
uint amount = pendingWithdrawals[msg.sender];
// Remember to zero the pending refund before
// sending to prevent re-entrancy attacks
pendingWithdrawals[msg.sender] = 0;
msg.sender.transfer(amount);
}
function enterBidForToken(uint tokenIndex) payable {
if (tokenIndex >= 10000) revert();
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] == 0x0) revert();
if (tokenIndexToAddress[tokenIndex] == msg.sender) revert();
if (msg.value == 0) revert();
Bid existing = tokenBids[tokenIndex];
if (msg.value <= existing.value) revert();
if (existing.value > 0) {
// Refund the failing bid
pendingWithdrawals[existing.bidder] += existing.value;
}
tokenBids[tokenIndex] = Bid(true, tokenIndex, msg.sender, msg.value);
TokenBidEntered(tokenIndex, msg.value, msg.sender);
}
function acceptBidForToken(uint tokenIndex, uint minPrice) {
if (tokenIndex >= 10000) revert();
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] != msg.sender) revert();
address seller = msg.sender;
Bid bid = tokenBids[tokenIndex];
if (bid.value == 0) revert();
if (bid.value < minPrice) revert();
tokenIndexToAddress[tokenIndex] = bid.bidder;
balanceOf[seller]--;
balanceOf[bid.bidder]++;
Transfer(seller, bid.bidder, 1);
tokensOfferedForSale[tokenIndex] = Offer(false, tokenIndex, bid.bidder, 0, 0x0);
uint amount = bid.value;
tokenBids[tokenIndex] = Bid(false, tokenIndex, 0x0, 0);
pendingWithdrawals[seller] += amount;
TokenBought(tokenIndex, bid.value, seller, bid.bidder);
}
function withdrawBidForToken(uint tokenIndex) {
if (tokenIndex >= 10000) revert();
if (!allTokensAssigned) revert();
if (tokenIndexToAddress[tokenIndex] == 0x0) revert();
if (tokenIndexToAddress[tokenIndex] == msg.sender) revert();
Bid bid = tokenBids[tokenIndex];
if (bid.bidder != msg.sender) revert();
TokenBidWithdrawn(tokenIndex, bid.value, msg.sender);
uint amount = bid.value;
tokenBids[tokenIndex] = Bid(false, tokenIndex, 0x0, 0);
// Refund the bid money
msg.sender.transfer(amount);
}
}
2) Following the creation, I would like to fetch some data from Oraclize, and depending on the forex USD/GBP rate transfer a token or not.
The following code is from the Oraclize example contract:
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
contract ExampleContract is usingOraclize {
string public EURGBP;
string public value = "0.88086";
event LogPriceUpdated(string price);
event LogNewOraclizeQuery(string description);
function ExampleContract() payable public{
updatePrice();
}
function __callback(bytes32 myid, string result) public {
if (msg.sender != oraclize_cbAddress()) revert();
EURGBP = result;
if (keccak256(result) != keccak256(value)) {
LogPriceUpdated(value);
}
else {
LogPriceUpdated(result);
}
}
function updatePrice() payable public{
if (oraclize_getPrice("URL") > this.balance) {
LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("URL", "json(http://api.fixer.io/latest?symbols=USD,GBP).rates.GBP");
}
}
}
Based on my understanding, I could make the main token contract inherit from the oracle contract. And the main contract should inherit all the functions from the oracle token contract.
Oraclize is a paid service, so I should make the updatePrice() always payable, and put something like 1 ether on the upper right side of Remix IDE.
Problems are double:
a) In the Official Remix IDE (JS VM), while the token contract executes, the Oraclize contract fails with "reverting the contract to initial state" message. Is it related to Oracle being paid? Because I always put like 1 ether in the top right side of the IDE. But I don´t know how to address this exactly.
b) In the Remix fork that Oraclize has (https://dapps.oraclize.it/browser-solidity/) using JS VM too, it will execute the query but it fails executing the token, with an "Invalid op code" message for the "calls". So I can't even get the token symbol.
Questions:
1) Also, besides the IDE issues, my doubt resides, in how should I proceed in giving a token on the condition that for example the USD/GBP value is X.
I assume that I should use the getToken() function in the main contract, check if the exchange rate is x, and assign the token? How I could do this effectively?
2) Should I use one of the events implemented in the main token contract, or it has got nothing to do with it?
I'm not sure if I can address you design questions as it seems more like a business problem than a coding/design issue (or I may not be understanding the question). If getToken is your point of sale and you want to reject any requests when the exchange rate is too low, then just make that a condition you check with a require statement. However, I will note that from the technical standpoint, you can't read events in a Solidity contract. You can only listen for them in a client which will receive the event(s) when the transaction is successfully mined.
I can, however, address your IDE issues. The reason for the failures is oraclizeAPI is dependent on already deployed contracts. They have a modifier which sets up the internal network of the contract depending on which environment it's running:
function oraclize_setNetwork(uint8 networkID) internal returns(bool){
if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet
OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
oraclize_setNetworkName("eth_mainnet");
return true;
}
if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet
OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
oraclize_setNetworkName("eth_ropsten3");
return true;
}
if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet
OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
oraclize_setNetworkName("eth_kovan");
return true;
}
if (getCodeSize(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48)>0){ //rinkeby testnet
OAR = OraclizeAddrResolverI(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48);
oraclize_setNetworkName("eth_rinkeby");
return true;
}
if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge
OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
return true;
}
if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide
OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
return true;
}
if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity
OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
return true;
}
return false;
}
When you run your example contract in JS VM (which is it's own sandbox), it doesn't have access to those contracts and the call fails. It works if you switch environments to Ropsten/Rinkeby and connect through MetaMask.