I am getting this error in testing my upgradeable smart contract.
I am really stuck with this can anyone help me get out of this?
contracts/StakingContract.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "#openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
contract StakingContract is ERC20Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
using SafeMathUpgradeable for uint256;
using AddressUpgradeable for address;
using SafeERC20Upgradeable for IERC20Upgradeable;
event TokensStaked(address _tokenStaker, uint256 _amount, uint256 unlockTime);
event TokenUnstaked(address _tokenStaker, uint256 _amount);
// Variable that prevents _deposit method from being called 2 times
bool private locked;
// The total staked amount
uint256 public totalStaked;
mapping (address => uint256) public stakeBalances;
mapping(address => uint256) private timestamp;
function initialize(uint256 initialSupply) public initializer {
__ERC20_init("MyToken", "TKN");
_mint(owner(), initialSupply);
}
function stakeTokens(address token, uint amount) external {
stakeBalances[msg.sender] = stakeBalances[msg.sender].add(amount);
timestamp[msg.sender] = block.timestamp.add(30 days);
require(IERC20Upgradeable(token).allowance(msg.sender, address(this)) >= amount, "Check the token allowance");
require(IERC20Upgradeable(token).transferFrom(msg.sender, address(this), amount), "Transfer failed!");
totalStaked = totalStaked.add(amount);
emit TokensStaked(msg.sender, amount, timestamp[msg.sender]);
}
function unstakeTokens(address token, uint256 amount) external nonReentrant() {
require(amount <= stakeBalances[msg.sender], "Sorry! You don't have sufficient stake balance.");
require(block.timestamp >= timestamp[msg.sender], "Sorry! you cannot withdraw tokens before your stake time.");
stakeBalances[msg.sender] = stakeBalances[msg.sender].sub(amount);
require(IERC20Upgradeable(token).transfer(msg.sender, amount));
totalStaked = totalStaked.sub(amount);
emit TokenUnstaked(msg.sender, amount);
}
function ownerWithdraw(address token) external onlyOwner() nonReentrant() {
require(IERC20Upgradeable(token).transfer(owner(), totalStaked), "Transfer Failed!");
uint256 ownerStakedBalance = stakeBalances[msg.sender];
stakeBalances[msg.sender] = stakeBalances[msg.sender].sub(ownerStakedBalance);
totalStaked = totalStaked.sub(totalStaked);
}
}
test/StakingContract.test.js
const { accounts, contract, web3 } = require('#openzeppelin/test-environment');
const { expect } = require('chai');
const { TestHelper } = require('#openzeppelin/cli');
const { Contracts, ZWeb3 } = require('#openzeppelin/upgrades');
// Import utilities from Test Helpers
const { BN, expectEvent, expectRevert } = require('#openzeppelin/test-helpers');
ZWeb3.initialize(web3.currentProvider);
const Box = Contracts.getFromLocal('StakingContract');
describe('StakingContract', function () {
const [ owner, other ] = accounts;
beforeEach(async function () {
this.project = await TestHelper();
this.proxy = await this.project.createProxy(Box);
});
it('retrieve returns a value previously stored', async function () {
// Use large integer comparisons
expect(await this.proxy.methods.owner().call()).to.equal(owner);
});
});
it gives the following error:
0 passing (864ms)
1 failing
1) StakingContract
retrieve returns a value previously stored:
AssertionError: expected '0x0000000000000000000000000000000000000000' to equal '0xA05c7D52b924DceB23a766ccB1e91e67b4aCF014'
+ expected - actual
-0x0000000000000000000000000000000000000000
+0xA05c7D52b924DceB23a766ccB1e91e67b4aCF014
I have tried to fix it with other things but the still issue persists.
Thanks in advance.
Related
I am trying to create a test around a contract, but I am having problems understanding how to sign it in a test environment
This is my contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.9 <0.9.0;
import "#divergencetech/ethier/contracts/crypto/SignatureChecker.sol";
import "#divergencetech/ethier/contracts/crypto/SignerManager.sol";
import "#divergencetech/ethier/contracts/erc721/BaseTokenURI.sol";
import "#divergencetech/ethier/contracts/erc721/ERC721ACommon.sol";
import "#divergencetech/ethier/contracts/erc721/ERC721Redeemer.sol";
import "#divergencetech/ethier/contracts/sales/FixedPriceSeller.sol";
import "#divergencetech/ethier/contracts/utils/Monotonic.sol";
import "#openzeppelin/contracts/token/common/ERC2981.sol";
import "#openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "#openzeppelin/contracts/utils/structs/EnumerableSet.sol";
interface ITokenURIGenerator {
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// #author divergence.xyz
contract TestBirds is
ERC721ACommon,
BaseTokenURI,
FixedPriceSeller,
ERC2981,
AccessControlEnumerable
{
using EnumerableSet for EnumerableSet.AddressSet;
using ERC721Redeemer for ERC721Redeemer.Claims;
using Monotonic for Monotonic.Increaser;
/**
#notice Role of administrative users allowed to expel a Player from the
mission.
#dev See expelFromMission().
*/
bytes32 public constant EXPULSION_ROLE = keccak256("EXPULSION_ROLE");
constructor(
string memory name,
string memory symbol,
string memory baseTokenURI,
address payable beneficiary,
address payable royaltyReceiver
)
ERC721ACommon(name, symbol)
BaseTokenURI(baseTokenURI)
FixedPriceSeller(
2.5 ether,
Seller.SellerConfig({
totalInventory: 10_000,
lockTotalInventory: true,
maxPerAddress: 0,
maxPerTx: 0,
freeQuota: 125,
lockFreeQuota: false,
reserveFreeQuota: true
}),
beneficiary
)
{
_setDefaultRoyalty(royaltyReceiver, 1000);
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
#dev Mint tokens purchased via the Seller.
*/
function _handlePurchase(
address to,
uint256 n,
bool
) internal override {
_safeMint(to, n);
}
/**
#dev Record of already-used signatures.
*/
mapping(bytes32 => bool) public usedMessages;
/**
#notice Mint tokens.
*/
function mintPublic(
address to,
bytes32 nonce,
bytes calldata sig
) external payable {
signers.requireValidSignature(
signaturePayload(to, nonce),
sig,
usedMessages
);
_purchase(to, 1);
}
function alreadyMinted(address to, bytes32 nonce)
external
view
returns (bool)
{
return
usedMessages[
SignatureChecker.generateMessage(signaturePayload(to, nonce))
];
}
/**
#dev Constructs the buffer that is hashed for validation with a minting
signature.
*/
function signaturePayload(address to, bytes32 nonce)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(to, nonce);
}
/**
#dev Required override to select the correct baseTokenURI.
*/
function _baseURI()
internal
view
override(BaseTokenURI, ERC721A)
returns (string memory)
{
return BaseTokenURI._baseURI();
}
/**
#notice If set, contract to which tokenURI() calls are proxied.
*/
ITokenURIGenerator public renderingContract;
/**
#notice Sets the optional tokenURI override contract.
*/
function setRenderingContract(ITokenURIGenerator _contract)
external
onlyOwner
{
renderingContract = _contract;
}
/**
#notice If renderingContract is set then returns its tokenURI(tokenId)
return value, otherwise returns the standard baseTokenURI + tokenId.
*/
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
if (address(renderingContract) != address(0)) {
return renderingContract.tokenURI(tokenId);
}
return super.tokenURI(tokenId);
}
/**
#notice Sets the contract-wide royalty info.
*/
function setRoyaltyInfo(address receiver, uint96 feeBasisPoints)
external
onlyOwner
{
_setDefaultRoyalty(receiver, feeBasisPoints);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721ACommon, ERC2981, AccessControlEnumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
It compiles ok, but when I tried to create a test for minting, I must generate a valid signature...
This is the test
const { expect } = require('chai');
describe("TestBirds", function () {
it ("Should return correct name, URI, owner and beneficiary", async function () {
const [owner, addr1] = await hre.ethers.getSigners()
provider = ethers.provider
const TestBirdsContract = await hre.ethers.getContractFactory("TestBirds")
const testBirdsContractDeployed = await TestBirdsContract.deploy(
"TestBirds",
"APFP",
"https://test.url/",
owner.address,
owner.address)
console.log(await provider.getBalance(owner.address));
await testBirdsContractDeployed.deployed()
const nonce = await ethers.provider.getTransactionCount(owner.address, "latest")
await testBirdsContractDeployed.mintPublic(owner.address, nonce, signature???)
expect(await testBirdsContractDeployed.name()).to.equal("TestBirds")
expect(await testBirdsContractDeployed.tokenURI(0), "https://test.url/0")
expect(await testBirdsContractDeployed.ownerOf(0)).to.equal(owner.address)
})
})
How should I sing this in order to work? I can not test the contract without the sign. If I remove the signature param from the contract it works, but that is not what I want.
Thanks
It seems that the only missing was to add a signer. This seems to work for your test contract...
import { expect } from "chai";
import { ethers } from "hardhat";
describe("Test signature", function () {
it("deploy tester contract, and send signed message", async function () {
const TestSignature = await ethers.getContractFactory("TestSignature",owner);
const testSignature = await TestSignature.deploy();
await testSignature.deployed();
const [owner] = await ethers.getSigners();
// missing line
testSignature.addSigner(owner.address);
const params = ethers.utils.solidityPack(
["address", "uint256", "bytes32"],
[owner.address, "10", ethers.utils.keccak256("0x66")]
);
const signed = await owner.signMessage(params);
console.log("owner address", owner.address);
await testSignature.mint(
owner.address,
"10",
ethers.utils.keccak256("0x66"),
signed
);
});
});
I've attempted the following, but without much success yet:
import { expect } from "chai";
import { ethers } from "hardhat";
describe("Test signature", function () {
it("deploy tester contract, and send signed message", async function () {
const TestSignature = await ethers.getContractFactory("TestSignature");
const testSignature = await TestSignature.deploy();
await testSignature.deployed();
const [owner] = await ethers.getSigners();
const params = ethers.utils.solidityPack(
["address", "uint256", "bytes32"],
[owner.address, "10", ethers.utils.keccak256("0x66")]
);
const signed = await owner.signMessage(params);
console.log("owner address", owner.address);
await testSignature.mint(
owner.address,
"10",
ethers.utils.keccak256("0x66"),
signed
);
});
});
That is a test against the following contract:
pragma solidity >=0.8.0 <0.9.0;
// SPDX-License-Identifier: MIT
import "./SignatureChecker.sol";
contract TestSignature {
using EnumerableSet for EnumerableSet.AddressSet;
using SignatureChecker for EnumerableSet.AddressSet;
EnumerableSet.AddressSet internal signers;
constructor() {
signers.add(msg.sender);
}
mapping(bytes32 => bool) public usedMessages;
function mint(
address to,
uint256 price,
bytes32 nonce,
bytes calldata sig
) external payable {
signers.requireValidSignature(
signaturePayload(to, price, nonce),
sig,
usedMessages
);
}
/**
#dev Constructs the buffer that is hashed for validation with a minting signature.
*/
function signaturePayload(
address to,
uint256 price,
bytes32 nonce
) public pure returns (bytes memory) {
return abi.encodePacked(to, price, nonce);
}
function generateMessage(bytes memory data) public pure returns (bytes32) {
return SignatureChecker.generateMessage(data);
}
}
From what I understood, the signed message should match the message, and the ECDSA.toEthSignedMessageHash(data)
appends the \x19Ethereum Signed Message:\n to the beggining of the message. After it matches, it can recover the signer address, but it doesn't seem to work quite right yet.
I have a roulette smart contract, that uses another smart contract to provide it with random numbers. The issue i'm having is during compilation, i get the error:
TypeError: Type contract IRandomNumberGenerator is not implicitly convertible to expected type address.
project:/contracts/Roulette.sol:34:29:
randomNumberGenerator = IRandomNumberGenerator(randomNumberGenerator);
I'm not exactly sure where i'm going wrong, i've seen this code used in other contracts. Here is my full code, any help would be much appreciated.
// SPDX-License-Identifier: UNLICENSED"
pragma solidity ^0.8.7;
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "./IRandomNumberGenerator.sol";
contract Roulette is Ownable {
using SafeERC20 for IERC20;
IERC20 public gameToken;
uint256[100] internal randomNumbers;
IRandomNumberGenerator internal randomNumberGenerator;
// ensure caller is the random number generator contract
modifier onlyRandomGenerator() {
require(msg.sender == address(randomNumberGenerator), "Only random generator");
_;
}
constructor(address tokenAddress) {
gameToken = IERC20(tokenAddress);
}
function setRandomNumberGenerator(address randomNumberGenerator) external onlyOwner {
randomNumberGenerator = IRandomNumberGenerator(randomNumberGenerator);
}
function getRandomNumber() internal onlyOwner returns (uint) {
uint result = randomNumbers[randomNumbers.length-1];
delete randomNumbers[randomNumbers.length-1];
return result;
}
function numberGenerated(uint randomNumber) external onlyRandomGenerator {
randomNumbers = expand(randomNumber);
}
// generate 100 random numbers from the random number seed
function expand(uint256 randomValue) public pure returns (uint256[] memory expandedValues) {
expandedValues = new uint256[](100);
for (uint256 i = 0; i < 100; i++) {
expandedValues[i] = uint256(keccak256(abi.encode(randomValue, i)));
}
return expandedValues;
// TODO - ensure random numbers are roulette numbers
}
}
// SPDX-License-Identifier: UNLICENSED"
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "./IRoulette.sol";
contract RandomNumberGenerator is VRFConsumerBase {
address public roulette;
bytes32 internal keyHash;
uint256 internal fee;
uint256 internal randomResult;
// modifier to check if caller of owner is the admin
modifier onlyRoulette() {
require(msg.sender == roulette, "Caller to function is not the roulette contract");
_;
}
constructor(address _roulette)
VRFConsumerBase(
0xa555fC018435bef5A13C6c6870a9d4C11DEC329C, // VRF Coordinator
0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06 // LINK Token
)
{
keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
fee = 0.1 * 10 ** 18;
roulette = _roulette;
}
function getRandomNumber() public onlyRoulette returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
IRoulette(roulette).numberGenerated(randomResult);
}
}
Found out the issue was having the same name for both the parameter and the variable.
Updated the function to:
function setRandomNumberGenerator(address _randomNumberGenerator) external onlyOwner {
randomNumberGenerator = IRandomNumberGenerator(_randomNumberGenerator);
}
I'm trying to create a factory contract which is used to mint ERC721 tokens, at two different prices depending on whether it's during presale.
I'm using the Access library from OpenZeppelin, and have my contract set up with two roles (plus the default administrator role). Some lines are excluded for brevity:
import "#openzeppelin/contracts/access/AccessControl.sol";
import "./Example.sol";
contract ExampleFactory is AccessControl {
// ...
bool public ONLY_WHITELISTED = true;
uint256 public PRESALE_COST = 6700000 gwei;
uint256 public SALE_COST = 13400000 gwei;
uint256 MAX_PRESALE_MINT = 2;
uint256 MAX_LIVE_MINT = 10;
uint256 TOTAL_SUPPLY = 100;
// ...
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
bytes32 public constant ROLE_PRESALE = keccak256("ROLE_PRESALE");
// ...
constructor(address _nftAddress) {
nftAddress = _nftAddress;
// Grant the contract deployer the default admin role: it will be able
// to grant and revoke any roles
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(ROLE_MINTER, msg.sender);
_setupRole(ROLE_PRESALE, msg.sender);
}
function mint(uint256 _mintAmount, address _toAddress) public payable {
// If the user doesn't have the minter role then require payment
if (hasRole(ROLE_MINTER, msg.sender) == false) {
if (ONLY_WHITELISTED == true) {
// If still in whitelist mode then require presale role & enough value
require(hasRole(ROLE_PRESALE, msg.sender), "address is not whitelisted");
require(msg.value >= PRESALE_COST * _mintAmount, "tx value too low for quantity");
} else {
require(msg.value >= SALE_COST * _mintAmount, "tx value too low for quantity");
}
}
// Check there are enough tokens left to mint
require(canMint(_mintAmount), "remaining supply too low");
Example token = Example(nftAddress);
for (uint256 i = 0; i < _mintAmount; i++) {
token.mintTo(_toAddress);
}
}
function canMint(uint256 _mintAmount) public view returns (bool) {
if (hasRole(ROLE_MINTER, msg.sender) == false) {
if (ONLY_WHITELISTED == true) {
require((_mintAmount <= MAX_PRESALE_MINT), "max 2 tokens can be minted during presale");
} else {
require((_mintAmount <= MAX_LIVE_MINT), "max 10 tokens can be minted during sale");
}
}
Example token = Example(nftAddress);
uint256 issuedSupply = token.totalSupply();
return issuedSupply < (TOTAL_SUPPLY - _mintAmount);
}
}
There are a couple of different paths to mint:
If the user has ROLE_MINTER, they can mint without payment or limits
If ONLY_WHITELISTED is true, the transaction must have enough value for presale price, and they must have ROLE_PRESALE
If ONLY_WHITELISTED is false, anyone can mint
I've written a script to test minting:
const factoryContract = new web3Instance.eth.Contract(
FACTORY_ABI,
FACTORY_CONTRACT_ADDRESS,
{ gasLimit: '1000000' }
);
console.log('Testing mint x3 from minter role')
try {
const result = await factoryContract.methods
.mint(3, OWNER_ADDRESS)
.send({ from: OWNER_ADDRESS });
console.log(' ✅ Minted 3x. Transaction: ' + result.transactionHash);
} catch (err) {
console.log(' 🚨 Mint failed')
console.log(err)
}
Running this successfully mints 3 tokens to the factory owner. No value is attached to this call, and it's minting more than the maximum, so in order for it to be successful it has to follow the ROLE_MINTER path.
However, if I call hasRole from the same address, the result is false which doesn't make sense.
const minterHex = web3.utils.fromAscii('ROLE_MINTER')
const result = await factoryContract.methods.hasRole(minterHex, OWNER_ADDRESS).call({ from: OWNER_ADDRESS });
// result = false
If I try to run the test mint script from another address (with no roles) it failed as expected, which suggests roles are working but I'm using hasRole wrong?
const minterHex = web3.utils.fromAscii('ROLE_MINTER')
This JS snippet returns the hex representation of the ROLE_MINTER string: 0x524f4c455f4d494e544552
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
But this Solidity snippet returns the keccak256 hash of the ROLE_MINTER string: 0xaeaef46186eb59f884e36929b6d682a6ae35e1e43d8f05f058dcefb92b601461
So when you're querying the contract if the OWNER_ADDRESS has the role 0x524f4c455f4d494e544552, it returns false because this address doesn't have this role.
You can calculate the hash using the web3.utils.soliditySha3() function (docs).
const minterHash = web3.utils.soliditySha3('ROLE_MINTER');
const result = await factoryContract.methods.hasRole(minterHash, OWNER_ADDRESS).call();
Also note that the OpenZeppelin hasRole() function doesn't check for msg.sender, so you don't need to specify the caller inside the call() function. Just the 2nd argument of the hasRole() as the account that you're asking about their role.
Overview
I am working on a project for a Blockchain Developer Course, the project must be tested with Ganache because the Reviewer Team for the course will use Ganache.
The Smart Contract that I am working right now works with two different smart contracts, one is for data storage and the other is for the application purposes (user interaction).
When an user interacts with the registerOracle function the smart contract will ask for 1 ether to generate 1 oracle (this oracle will have an ID and 3 Indexes).
I tested the Smart Contract on Remix and everything works find but when I try to test the oracle generator function in Ganache it gives me a revert error.
Project URL
The project's files are in my Github's repository along with some screenshot I took showcasting the procedure to test the smart contract on Remix and the error I get on Ganache.
The code is too extend, but I will be posting here the relevant parts that are giving me the errors. The complete code can be seen on my repository.
TestingEnv.js File
const Web3 = require('web3');
const fs = require('fs').promises;
async function main () {
/**
* IGNORE FROM HERE
*/
const web3 = new Web3(new Web3.providers.WebsocketProvider("HTTP://127.0.0.1:8545"));
const appABI = (JSON.parse(await fs.readFile("./bin/appAbi.json", "utf8"))).abi;
const appBYTECODE = (JSON.parse(await fs.readFile("./bin/appByteCode.json", "utf8"))).bytecode;
const dataABI = (JSON.parse(await fs.readFile("./bin/dataAbi.json", "utf8"))).abi;
const dataBYTECODE = (JSON.parse(await fs.readFile("./bin/dataByteCode.json", "utf8"))).bytecode;
const owner = (await web3.eth.getAccounts())[0];
const appContract = await new web3.eth.Contract(appABI).deploy({data: '0x' + appBYTECODE})
.send({from: owner, gasLimit: 6000000, gasPrice: web3.utils.toWei('5', 'gwei')});
const dataContract = await new web3.eth.Contract(dataABI).deploy({data: '0x' + dataBYTECODE})
.send({from: owner, gasLimit: 6000000, gasPrice: web3.utils.toWei('5', 'gwei')});
const appAddress = appContract._address;
const dataAddress = dataContract._address;
await appContract.methods.registerDataContract(dataAddress).send({from: owner});
await dataContract.methods.registerApplicationContract(appAddress).send({from: owner});
/**
* TO HERE
*/
/**
* REVERT ERROR - STARTS
*/
const oracleFee = await web3.utils.toWei("1", "ether");
const server = (await web3.eth.getAccounts())[2];
// I AM REGISTERING 20 ORACLES
for (var i=0; i<20; i++) {
await appContract.methods.registerOracle().send({from: server, value: oracleFee});
await new Promise(resolve => setTimeout(resolve, 2000));
};
const totalOracles = await appContract.methods.getTotalOracles().call({from: server});
console.log(`Total Numbers of Oracles Registered: ${totalOracles}`);
for (var i = 0; i<totalOracles; i++) {
var indexes = await appContract.methods.getOraceIndexes(i).call({from: server});
if (i >= 0 && i <= 9) {
console.log(`Oracle 0${i} indexes: ${indexes._index1.toString()} ${indexes._index2.toString()} ${indexes._index2.toString()}`);
} else {
console.log(`Oracle ${i} indexes: ${indexes._index1.toString()} ${indexes._index2.toString()} ${indexes._index2.toString()}`);
};
};
};
main();
FlightSuretyApp.sol Contract
pragma solidity ^0.4.24;
interface iFlightSuretyData {
function registerOracle(address server, uint8 index1, uint8 index2, uint8 index3) external payable;
}
import "./SafeMath.sol";
contract FlightSuretyApp {
using SafeMath for uint256;
bool operationalStatus;
address owner;
iFlightSuretyData FlightSecuretyData;
constructor() public {
operationalStatus = true;
owner = msg.sender;
}
modifier requireOwner() {
require(msg.sender == owner, "Owner is required");
_;
}
modifier requireOperational() {
require(operationalStatus == true, "Contract is not operational");
_;
}
function registerDataContract(address dataContract) external
requireOwner {
FlightSecuretyData = iFlightSuretyData(dataContract);
}
uint256 constant ORACLE_REGISTRATION_FEE = 1 ether;
modifier requireOracleRegistrationFee() {
require(msg.value == ORACLE_REGISTRATION_FEE, "Oracle Registration Cost 1 ether");
_;
}
function registerOracle() external payable
requireOperational
requireOracleRegistrationFee {
(uint8 index1, uint8 index2, uint8 index3) = indexesThrown();
FlightSecuretyData.registerOracle.value(msg.value)(msg.sender, index1, index2, index3);
}
function indexesThrown() private view returns(uint8 _index1, uint8 _index2, uint8 _index3)
{
uint8 index1 = generateIndex1();
uint8 index2 = generateIndex2(index1);
uint8 index3 = generateIndex3(index1, index2);
return (index1, index2, index3);
}
function generateIndex1() private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
return value;
}
function generateIndex2(uint8 _index1) private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
while(value == _index1) {
time = SafeMath.add(time, 500);
difficulty = SafeMath.add(difficulty, 700);
value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
}
return value;
}
function generateIndex3(uint8 _index1, uint8 _index2) private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
while((value == _index1) || (value == _index2)) {
time = SafeMath.add(time, 500);
difficulty = SafeMath.add(difficulty, 700);
value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
}
return value;
}
}
FlightSuretyData.sol
import "./SafeMath.sol";
contract FlightSuretyData {
using SafeMath for uint256;
bool operationalStatus;
address owner;
address appContract;
constructor() public {
operationalStatus = true;
owner = msg.sender;
airlines[owner].registrationStatus = true;
}
modifier requireOwner() {
require(msg.sender == owner, "Require contract owner");
_;
}
modifier requireApplication() {
require(msg.sender == appContract, "Require application");
_;
}
modifier requireOperational() {
require(operationalStatus == true, "Contract is not operational");
_;
}
function registerApplicationContract(address application) external
requireOwner
requireOperational {
appContract = application;
}
struct oracle {
uint8 index1;
uint8 index2;
uint8 index3;
mapping(bytes32 => bool) voteState;
}
struct oracleServer {
mapping(uint256 => oracle) oracles;
uint256 numberOfOracles;
}
mapping(address => oracleServer) private oracleServers;
function registerOracle(address server, uint8 index1, uint8 index2, uint8 index3) external payable
requireOperational
requireApplication {
uint256 counter = oracleServers[server].numberOfOracles;
oracleServers[server].oracles[counter].index1 = index1;
oracleServers[server].oracles[counter].index2 = index2;
oracleServers[server].oracles[counter].index3 = index3;
counter = SafeMath.add(counter, 1);
oracleServers[server].numberOfOracles = counter;
}
}
How to Run the Project?
It is easy, just install the dependencies and run the TestingEnv.js file.
My Environment Specifications
Windows 10 Home version 21H1
Ganache version 2.5.4 (Use the Ganache Desktop Application from Ganache and not some dependencies)
Node version 11.0.0
Solidity version 0.4.24
Proof that Works on Remix
Proof that Doesn't Work on Ganache
Request
How can I solve it? I am stuck on my project because I can make the project work, I've teste others functions of my smart contracts and they are working fine, but when I try to test the oracle generator it gives an error and doesn't work.
What am I missing?
I created an ERC20 SC, this is the initial supply amount 100000000000. But, when I run unit test (truffle test) to show the total balance amount of the accounts[0] and the actual amount is 99999998877, expected amount should be 100000000000. Can someone explain to me, why that's happened?
Thank you.
it("should return the total supply", function() {
return CToken.deployed().then(function(instance){
return tokenInstance.totalSupply.call();
}).then(function(result){
assert.equal(result.toNumber(), 100000000000, 'total supply is wrong');
})
});
it("should return the balance of token owner", function() {
var token;
return CToken.deployed().then(function(instance){
token = instance
return tokenInstance.balanceOf.call(accounts[0]);
}).then(function(result){
assert.equal(result.toNumber(), 99999998877, 'balance is wrong');
})
});
Contract code:
pragma solidity >=0.4.21 <0.6.0;
import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol";
/**
* #title BearToken is a basic ERC20 Token
*/
contract CToken is StandardToken, Ownable{
uint256 public totalSupply;
string public name;
string public symbol;
uint32 public decimals;
/**
* #dev assign totalSupply to account creating this contract
*/
constructor() public {
symbol = "CT";
name = "CToken";
decimals = 18;
totalSupply = 100000000000;
owner = msg.sender;
balances[msg.sender] = totalSupply;
//emit Transfer(0x0, msg.sender, totalSupply);
}
}
Your total supply is 10^29 (10^11 tokens, each token has 10^18 decimal points), which is not something javascript number can safely handle. https://docs.ethers.io/ethers.js/html/notes.html#why-can-t-i-just-use-numbers
web3 returns a BN instance, don't convert it to number.
You can assert like this:
const BN = web3.utils.BN
const ten = new BN("10")
const expected = ten.pow(new BN("27"))
assert(result.eq(expected), "Result doesn't match expected value")