I am making a simple smart contract that is essentially a ledger that people can sign with a string (UI to come) and then pass onto a next person (using their ether address). I just wanted to create something that could be passed from person to person while recording its journey.
The logic of 'transferring' the signing-ledger is all done within the smart contract, with it existing as a mapping and the key value of an address changing from 0 to 1 signifying ownership (1 person owning it at a time). Because there's no actual transfer of ether/actual monetary value, where would actual ethereum transactions be occurring in this contract?
Also to sign the ledger I verify that the public key signing it has 1 as its value in the mapping, but how would I check that that person owns that public key (using a private key)?
my solidity code so far:
pragma solidity ^0.4.4;
contract Pass{
mapping(address => bool) ownership;
mapping(address => string) notes;
constructor(address genesis) public {
ownership[genesis] = true; //this address starts with it
}
function checkOwnership(address p) public view returns(bool){
if(ownership[p]){
return true;
}
return false;
}
function sign(string signedNote) public returns(uint){ // 1 on success 0 on fail
if(checkOwnership(msg.sender)){ //if msg.sender owns the note
notes[msg.sender] = signedNote;
return 1;
}
return 0;
}
function pass(address recipient) public returns(uint){ // 1 on success 0 on fail
if(checkOwnership(msg.sender)){ //if msg.sender owns the note
ownership[msg.sender] = 0;
ownership[recipient] = 1;
return 1;
}
return 0;
}
function viewNotes(address participant) public returns(string){ // signed note on success nothing on fail
if(notes[participant] !== 0){
return (notes(participant));
}
}
}
The logic of 'transferring' the signing-ledger is all done within the smart contract, with it existing as a mapping and the key value of an address changing from 0 to 1 signifying ownership (1 person owning it at a time)
This is a common pattern known as the owner pattern. You can simplify this by simply keeping track of a single owner address and updating that, instead of using a mapping, since you only care about the current owner. Something as simple as:
address public owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
constructor() {
owner = msg.sender;
}
function transferOwnership(address _owner) onlyOwner {
owner = _owner;
}
Open Zeppelin has a more complete implementation of ownership here.
Because there's no actual transfer of ether/actual monetary value, where would actual ethereum transactions be occurring in this contract?
Transactions do not require ether movement. You can call any public/external function on your contract with a 0 value transaction, and pass data to it. The transaction will execute on the blockchain like any other, and run the code you invoke within the contract.
Also to sign the ledger I verify that the public key signing it has 1 as its value in the mapping, but how would I check that that person owns that public key (using a private key)?
You are already checking is msg.sender matches the whitelisted address. For basic transactions, this means that the transaction has been signed by the address in msg.sender (msg.sender can also be a contract, if another contract calls yours. To check who actually signed the transaction in all scenarios, you must use tx.origin).
Related
In the Remix, getICOMembers function works appropriately and returns all members of a specific ICO type after they are added to the icoMembers mapping.
mapping(uint256 => address[]) private icoMembers;
function getICOMembers(uint256 _icoType) external view onlyOwner returns (address[] memory)
{
return icoMembers[_icoType];
}
0 1
But Etherscan gives this error even if I connected by owner address.
deployer address owner address etherscan error
Also, this function has onlyOwner modifier too but it works.
ICOdata[] private ICOdatas;
function getICODatas() external view onlyOwner returns (ICOdata[] memory)
{
return ICOdatas;
}
getICODatas function output
I tried to add members by hardcoding instead of joining the token sale function, changing external to public but it still gives the same error.
Also, this is the constructor.
constructor(
address _token,
address payable _usdtWallet,
address _vestingContract
) {
require(
address(_token) != address(0),
"ERROR at Crowdsale constructor: Token contract address shouldn't be zero address."
);
require(
_usdtWallet != address(0),
"ERROR at Crowdsale constructor: USDT wallet address shouldn't be zero address."
);
require(
_vestingContract != address(0),
"ERROR at Crowdsale constructor: Vesting contract address shouldn't be zero address."
);
token = ERC20(_token);
usdtWallet = _usdtWallet;
totalAllocation = 0;
vestingContract = IVesting(_vestingContract);
transferOwnership(msg.sender);
}
A view function is usually invoked using a read-only call - not using a transaction.
Unlike transaction, a call is not signed by any private key. So you can specify any from address that is reflected as the value of msg.sender.
Then it depends on the specific implementation of the UI and of the node that processes the call. My guess is that Remix IDE uses the currently selected address from the accounts list as msg.sender (which passes the onlyOwner validation), while Etherscan uses the zero address (which fails the validation).
I created smart contract to transfer ETH from one account to another, ETH deduction occurs but send to other address(which is not specified). Please help me to resolve this problem.
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.12;
contract ETH{
address public buyer;
uint public amt;
address public seller;
constructor(){
seller = msg.sender;
}
function add(address payable _buyer) payable public{
buyer = _buyer;
payable(buyer).transfer(amt);
}
function bal() view public returns(uint){
return buyer.balance;
}
function s() payable public returns(uint){
return msg.value;
}
}
The default value of amt is 0 and your code does not set this property (to a non-zero value) anywhere.
Which effectively makes your .transfer(amt) function to send 0 ETH to the buyer and keep all the ETH, that you sent along with the transaction, in the contract.
If you want to redirect the sent amount, there's the msg.value global variable, which reflects the current value sent with the transaction.
payable(buyer).transfer(msg.value);
I have deployed contract A.
Now I am creating gateway contract B and I want to send some tokens of contract A to user address X using owner address.
Worth to mention that contract A owner is the same as contract B.
I do the following
contract A is Ownable { // this one already deployed by owner
constructor() {
owner = msg.sender; // owner address is 0x123
approve(msg.sender, totalSupply); // let's approve all tokens for owner
}
function transferFrom(address from, address to, uint256 value) public returns (bool) {
require(value <= allowed[from][msg.sender], "Not allowed!");
// let's skip other logic
}
}
contract B is Ownable { // gateway contract will be deployed and executed by same owner
A contractA = ETC20(0x111);
address payable X = 0x333;
constructor() {
owner = msg.sender; // owner address is 0x123
}
function giveAwayTokens(uint256 value) {
contractA.transferFrom(owner, X, value);
}
}
When I execute "giveAwayTokens" function from owner address (0x123), I get error "Not allowed!".
So I am a bit confused right now, because the allowance of owner from owner is max supply.
Or maybe the msg.sender is contractB itself?
Please enlighten me what I am doing wrong here, thank you
When ContractB calls ContractA, the msg.sender in ContractA is ContractB address.
Based on the code and the error message, the owner (0x123) didn't allow ContractB to spend their tokens.
You need to set the value of allowed[<owner>][<ContractB>] to be at least the amount of tokens that you want to send.
Most likely you have an approve() function (defined in the token standard) that you can use. In the linked example, the caller of the function would be the owner, the spender would be the ContractB and the value would be any value equal or higher than the amount of tokens that you want to send (mind the decimals).
Is it possible for the same contract to handle multiple ERC721 tokens? And if so, how?
Let’s say you’re making a game and you need to track two types of ERC721 tokens: unique Weapons and unique Vehicles.
You could have Structs for them, as follows:
struct Weapon {
uint256 IDNumber;
string type; // Sword, Bow&Arrow, Gun, Rifle, etc.
string specialFeature;
}
struct Vehicle {
uint256 IDNumber;
string type; // Car, Airplane, Boat, Spaceship, etc.
uint256 damageFactor;
}
To track their ownership, you could double the arrays managing them - for example instead of having the standard:
// Enumerable mapping from token ids to their owners
EnumerableMap.UintToAddressMap private _tokenOwners;
You would do:
// Enumerable mapping from token ids to their owners
EnumerableMap.UintToAddressMap private _weaponTokenOwners;
EnumerableMap.UintToAddressMap private _vehicleTtokenOwners;
(This may not be the most elegant way, but it's a start.)
The real question though is: how would you handle mandatory functions that are part of the ERC721 standard, such as balanceOf() and ownerOf()?
To be specific, are you allowed to say add an additional argument to these methods’ signatures to help indicate which particular Token you’re querying about?
For example, instead of this:
function balanceOf(address owner) public view override returns (uint256) {
}
You’d add a tokenName argument to the function’s signature, as follows:
function balanceOf(address owner, string tokenName) public view override returns (uint256) {
if(tokenName == “weapon”) {
return ownerAndHisWeaponTokensDictionary[owner].length;
}
else if(tokenName == “vehicle”) {
return ownerAndHisVehicleTokensDictionary[owner].length;
}
}
And you’d do something similar for ownerOf()?
Is this allowable?
And is this even the right approach tackling this - or is there a different way to reason about all of this and approach it differently?
My approach would be to define 3 separate contracts on 3 separate addresses:
address 0x123123 as the Weapons ERC-721 token contract
address 0x456456 as the Vehicles ERC-721 token contract
address 0x789789 as the actual game contract
In the game contract, you can then call the NFTs contracts to get or validate values:
function attack(uint attackerWeaponId) {
require(weaponsContract.isOwnerOf(msg.sender, attackerWeaponId));
// ...
}
The isOwnerOf() function takes 2 arguments, address owner and uint256 weaponId. Also, a user can probably own more weapons so that's why I'm showing the validation.
And the weapons contract balanceOf(address) would reflect the total amount of the Weapon NFTs that the user has.
mapping (address => Weapon[]) userOwnedWeapons;
function balanceOf(address owner) external view returns (uint256) {
return userOwnedWeapons[msg.sender].length;
}
I have a problem related to refund the users entered inside the solidity contract. I don't, have any idea if is possible iterate all the players of my contract and refund all of them with all the balance.I read in some tutorials, iterate inside the solidity contract cost a lot of gas depends of the numer of iterations.
contract Lottery{
address payable public manager;
string public name; // short name (up to 32 bytes)
address [] players;
uint256 nTickets;
address winner;
bool enable;
uint256 minimunContribution;
mapping(address => uint) public balances;
constructor (string memory LotteryName, uint minimun, address payable creator) public {
manager = creator;
name = LotteryName;
winner = address(0);
enable = true;
minimunContribution = minimun;
}
modifier restricted() {
require(msg.sender == manager, "Access forbidden");
_;
}
function enterInToLottery() public payable {
require(msg.value > minimunContribution && enable == true, "Insufficient funds to allow transfer");
players.push(msg.sender);
balances[msg.sender] += msg.value;
nTickets++;
}
//this function refund
function paybackEther(bool newfinished) public restricted {
enable = !newfinished;
selfdestruct(msg.sender);
}}
Thanks in advance to all.
Yes that can be problematic as it will use a lot of gas and may even hit limits. To solve this it is better to allow the users to withdraw the balance themselves, so they pay for the gas. Or in fact you can allow anybody to make that call. So you can offer a call refund(account:uint256) which transfers the balance (if any) to given account. Note that this would not be using msg.sender, so that anybody (including the admin) can do this transfer.
Keep in mind they need to know that they have a balance, so make sure you're emitting an event or similar. Also provide a balanceOf(address) call so they can check.
Hope this makes sense & works for you.