I am implementing a factory pattern contract and on my constructor I want to trigger a function which deposits into the contract
--Factory--
function newChild() {
Child child = new Child(potentialPayoutAmount);
children[_childId] = address(child);
}
function getChild()view public returns (address) {
return children[_campaignId];
}
--Child Contract--
address payable public spender;
constructor(uint256 _potentialPayoutAmount) {
autoDeposit(_potentialPayoutAmount)
}
function autoDeposit(uint256 _potentialPayoutAmount) {
depositedFor[receiver] = depositedFor[receiver] + _potentialPayoutamount;
}
So my problem is that I want the spender address in the child contract to be the account that is spending the money, even though the autoDeposit function is obviously being triggered from the factory contract.
Any suggestions would help. Happy to elaborate if I was unclear.
Thanks!
Related
Im new to Solidity, I got a problem that when I call purchaseCard function, it always returns the error The called function should be payable if you send value and the value you send should be less than your current balance. on Remix IDE.
I think the problem is at the complexity of my structs or I probably called variables not allowed. But I still cant find fix after many days researching.
These are my structs.
struct Card {
string name;
uint price;
}
mapping(uint => Card) public cards;
uint public numberOfTypes;
struct Purchase {
Card card;
uint purchaseDate;
}
struct User {
uint numberOfCards;
Purchase[] purchase;
bool exist;
}
mapping(address => User) public users;
And these are my functions, I will make it short.
// function addCard(string memory _name, uint _price) public isOwner;
// function removeCard(uint _id) public isOwner;
// function checkExistedUser(address _userAddress) public view returns(bool);
function purchaseCard(uint _id) public {
User storage user = users[msg.sender];
if (!checkExistedUser(msg.sender)) {
user.exist = true;
user.numberOfCards = 0;
}
Purchase storage purchase = user.purchase[user.numberOfCards];
purchase.card = cards[_id];
purchase.purchaseDate = block.timestamp;
user.numberOfCards++;
}
// function expiredCard(uint _id) public;
// function showRemainingDate(uint _id) public view returns(uint);
// function showPurchasedCards() public view returns (Purchase[] memory);
This is my full code: https://pastebin.com/4HXDZZVK
Thank you very much, I hope to learn more things.
In this case, you cannot create an empty 'space' for purchase array in storage before fill it because the type of this operation is an array and not a mapping!
To solve this issue, you can use the push() method (available only for storage array) to fill purchase() array into Purchase struct.
Following your logic, you must change purchaseCard() method in this way:
function purchaseCard(uint _id) public {
User storage user = users[msg.sender];
if (!checkExistedUser(msg.sender)) {
user.exist = true;
user.numberOfCards = 0;
}
user.purchase.push(Purchase(cards[_id], block.timestamp));
user.numberOfCards++;
}
In Solidity, If you have to send/receive ETHs then the payable function should be used.
Try this:
function purchaseCard(uint _id) public payable {
or add payable to your constructor.
pls refer to this: https://solidity-by-example.org/payable/
And btw pls next time share the complete code snippet.
I can't able to understand the entire code and flow.. but while debugging..
the revert occurs in the belowline of the purchasecard function
Purchase storage purchase = user.purchase[user.numberOfCards];
It seems like you are accessing the user mapping which does not contain any User Struct..
I think you forgot to assing the value to the user mapping in the addCard Function.
I may be wrong and I hope it helps..
so, First, I imported the simpleStorage contract and then wrote this function createNeewContracts() to push the contract address into an array
everything was going smooth and I got an idea
"why not just use a struct of two variables 1. string (name of the contract owner) and 2. address (of the contract the owner owns) and i can then have name of owner and his contract as a struct stored in an array named contractAndThereArray"
I could have used mapping but I used struct and array to do the work
I ran into a problem it say
"TypeError: Invalid type for argument in function call. Invalid implicit conversion from contract SimpleStorage1 to address requested."
here is the code:-
contract StorageFactory{
// SimpleStorage public simpleStorage;
struct ownerAndThereContracts {
string name;
address nf;
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
// mapping(string => address) y;
uint256 counter;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
// address j = simpleStorage;
}
function refering(string memory _name) public {
counter++;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
saveYourContracts.push(ownerAndThereContracts(_name,simpleStorage2)); // the error occurs here it says simpleStorage2 is not address but contract
}
}
The problem is with the function referring where i tried to refer the address of a contract with the owners name but seems there is a problem
Please,if someone can explain it. Please explain I need your help guys
i've been tried to solve it for hours now but nothing seems to fit
I tried to get into your logic and fixed your contract and solve your mistake. Specifically, your error states that you cannot insert an instance of a contract into a field with datatype address. In order to solve this problem you need to cast the contract instance in address datatype. You can see the contract in the following lines, I have also inserted some notes to let you understand what I have changed:
// SDPX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "./SimpleStorage1.sol";
contract StorageFactory{
uint256 counter;
struct ownerAndThereContracts{
string name;
address nf; // NOTE: I assume that it's the SimpleStorage address
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
}
function refering(string memory _name) public {
// NOTE: I assume that when creating new contract, then you must refering it directly to an owner.
// In this case, I retrieve the length of array in details the last element index.
counter = x.length-1;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
// NOTE: You must cast your contract instance to an address for put it into your struct (because the datatype is 'address')
saveYourContracts.push(ownerAndThereContracts(_name,address(simpleStorage2)));
}
}
Ok first i fixed your code, you are missing 2 casting, first to address and then to a paybale address.
Here:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.15;
contract SimpleStorage1{
}
contract StorageFactory{
// SimpleStorage public simpleStorage;
struct ownerAndThereContracts {
string name;
address nf;
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
// mapping(string => address) y;
uint256 counter;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
// address j = simpleStorage;
}
function refering(string memory _name) public {
counter++;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
address simpleStorage2Address = address(simpleStorage2); //first cast to address
address payable _finalCast = payable(simpleStorage2Address); // then cast to payable address
saveYourContracts.push(ownerAndThereContracts(_name, _finalCast));
}
But you should know that this is a very costy contract, you should take out all the process of saving the contract to a environment like c or java and only create the contract through solidity so the objects on memory wont cost you.
Anyway good luck!
From docs: contract-types
Explicit conversion to and from the address payable type is only
possible if the contract type has a receive or payable fallback
function. The conversion is still performed using address(x). If the
contract type does not have a receive or payable fallback function,
the conversion to address payable can be done using
payable(address(x))
I explained here contract-type vs address type
In Solidity a contract variable is really just an address under the
hood.
function sendGift(uint256 _mintAmount,address recipient) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
require(supply + _mintAmount<= availableSupplyForSale);
//require(_amount >= cost * _mintAmount);
require(coinToken.allowance(msg.sender,address(this))>=cost * _mintAmount);
coinToken.transferFrom(msg.sender, address(this),cost * _mintAmount);
if(supply<currentSupply){
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(recipient, supply + i);
}
}
else{
uint256[] memory tokenIds = walletOfOwner(address(this));
for(uint256 i=1;i<=_mintAmount;i++)
transferFrom(address(this),recipient,tokenIds[i]);
}
}
Do I need to use payable here? Contract does not take any matic. It only takes custom token as payment .
(bool os, ) = payable(admin).call{value: address(this).balance}("");
require(os);
Also since I am not taking any matic, will this above line necessary for withdraw assets from contract as an owner? I have a sense that this above line only is useful to withdraw eth/polygon.
I am a new blockchain kid. Please help.
The payable modifier of a function is required when your function accepts native tokens (ETH, BNB, MATIC, ... depending on the network).
So in this case, you can safely remove it from the function header.
// removed `payable`
function sendGift(uint256 _mintAmount,address recipient) public {
The low-level .call() also doesn't require using payable to send native tokens.
payable(admin).call{value: address(this).balance}("");
However, if you used the high-level .transfer(), then you'd need to cast the admin variable type address to its extension type address payable using the typecasting function.
// will not work as it's type `address`
admin.transfer(address(this).balance);
// need to cast type `address` to type `address payable`
payable(admin).transfer(address(this).balance);
In order to withdraw tokens from your contract address, you need to invoke the transfer() function (defined in the ERC-20 standard) on the token contract. Do not confuse it with the native transfer() function of address payable, these are two separate things, just with the same name.
interface IERC20 {
function transfer(address, uint256) external returns (bool);
}
contract MyContract {
function withdrawToken() {
IERC20(tokenContractAddress).transfer(recipient, amount);
}
}
I got stucked in thoughts guys and I need bit of clarification to move it forward.
(Description is about real problem, code is for best (I hope so..) understanding me)
I have main contract A that uses erc20 token and its transfer functions, there is also inherited Ownable and whitelist with accessing addresses of contracts e.g. B,
I passing A address to the B constructor
I created instance of A in B (because in B I calculate collateral and I want to split to two different contracts)
Protecting A using Ownable it's enough from accessing A from 3rd party while interacting with A from A, Ownable in B isnt work because can't use right msg.sender, without modifiers someone can create instance of B in his contract and have access to my A, isn't it?
Thanks in advance
EDIT: I change a code for more to understand
// SPDX-License-Identifier: MIT
pragma solidity 0.8;
contract Ownable {
mapping (address => bool) private whiteListed;
modifier onlyWhiteListed {
require(whiteListed[msg.sender] == true, "You're not whitelisted");
_;
}
constructor () {
whiteListed[msg.sender] = true;
}
function setWhiteListed(address addr, bool trueOrFalse) public onlyWhiteListed {
whiteListed[addr] = trueOrFalse;
}
function getWhiteListed(address addr) public view returns (bool) {
return whiteListed[addr];
}
}
contract A is Ownable {
B public b;
event LogMsgSender(address who);
constructor() {
b = new B(address(this));
//setWhiteListed(address(this),true);
setWhiteListed(address(b),true);
}
function callMe() public onlyWhiteListed { // here I can only get real caller msg.sender
emit LogMsgSender(msg.sender); // when interact with that contract, not outside of contract
}
function callSender(address sender) public onlyWhiteListed { // here I can get real caller msg.sender from other contract
emit LogMsgSender(sender); // but is it worth to passing addresses ?
} // and HERE is my question: is this aproach secure??
}
contract B is Ownable {
A public a;
constructor(address addr) { //in remix I can't deploy in one time while
a = A(addr); //deploying A, I have to deploy copying addresses of A and do it separately
} //and after deploying also setWhiteListed() to whiteList in A
function callMe() public onlyWhiteListed { // this call isn't good for interact with sender, it's exlusive for calling as contract B
a.callMe(); // copies of this contract can
}
function callSender() public onlyWhiteListed { // modifiers protect from 3rd party contracts but
a.callSender(msg.sender); // that way it only can be used by deployer and whitelisted, (without modifiers they aren't secure)
} // bad idea ofc is adding to whitelist all over and over and
// it's impossible to recognize which to add which not
}
contract C {
B public b;
constructor(address addr) {
b = B(addr);
}
function callMe() public { //when modifiers is added this contract can't call these functions
b.callMe(); // but with modifiers functions can't be used to get right sender address
}
function callSender() public {
b.callSender();
}
}
So now I'm deciding to inherite e.g. B is A and I simply get right sender, what do you think?
You've got a lot of syntax/logic errors in the code you posted. Not only are you missing onlyOwner modifiers, but your calls in B are via the type A: A.receiveToken() is not the same as a.receiveToken() ... so you've probably made several typos in posting your question (Should say a=A(aAddr); in the constructor etc).
The msg.sender will be "b" when b calls a.sendToken() but tx.origin will be unchanged. Checking msg.sender checks which contract called you. In other words, it is checking (inside onlyOwner of A.sendToken) whether b is the one that called a.sendToken().
Start by fixing all the errors and then insert some debug logging for yourself, so you can see how msg.sender is changing during the calls. You can also log tx.origin to see how that remains the original sender.
The point is that the owner of the A that B created is that particular instance of B (b). It's therefore "natural" that inside B, it can call a.whatever() as a's owner.
You didn't specify, but if you are using the Ownable contract from openzeppelin you need to pass the modifier onlyOwner for the methods that you want to be protected. Ex:
function sendToken(uint value) public onlyOwner {
//transferFrom
emit Sent(value);
}
I have simple smart contract in Solidity. I want to call the function getHello() after I deployed the smart contract (to see variable in deployed contract without calling it by myself). Can I do this?
pragma solidity 0.5.12;
contract Hello {
string public helloStr = "Hello, world 2!";
uint[] public nums = [10, 20, 30];
function getHello() public view returns (string memory) {
return helloStr;
}
function pushNewElement(uint newElement) public returns (uint) {
nums.push(newElement);
}
function popLastElement () public returns (uint) {
nums.pop();
}
function setHello(string memory newHello) public {
helloStr = newHello;
}
}
For getting public variable the compiler automatically formed function.
In you case you can get hello string with function with hash c660ab0e
Or use your function getHello().
For calling function(example, helloStr()) you should use:
{"jsonrpc":"2.0","method":"eth_call", "params":[{"to":"address your smart contract", "data":"0xc660ab0e"}, "latest"],"id":1}
Or use web3 with call:
https://web3js.readthedocs.io/en/v1.2.0/web3-eth.html#call
Yes, you will see "hello world 2" after deployed the contract but you will never be able to see "newHello" output. because it sets the empty string whenever you setHello() function is using.