Solidity Mapping, which can store approved addresses, and then those approved addressed are the only one who can change the rate of the token - mapping

// __ Mapping __
mapping (address => uint) approvedUsers;
// __ Function to add addresses to the mapping___
function _addApprover(address _approver, uint _i) public{
approvedUsers[_approver] += approvedUsers[_i];
}
// ___ user from mapping checked and if true then the rate can be change, else not_
function pricing(address _user, uint _rate) public{
require(approvedUsers[_user] == approvedUsers,"User not in the approvers list");
rate = _rate * (10 ** uint256(decimals())); }

I think you want authenticate some addresses to change the rate and other addresses are not able to do.
To do so, you should (There are other ways but this is easier) do this:
//First you declare owner to have access to approve or disapprove users
address owner;
//Then you declare mapping
mapping(address=>bool) approvedUsers;
//Automatically all addresses return false so no one has access to it.
//In constructor, you specify the owner
constructor(){
owner = msg.sender
}
//By using msg.sender, contract who deployed contract will be owner.
//A modify to make some functions just callable by owner
modifier isOwner(){
require(msg.sender == owner, "Access denied");
_;
}
//Now function to approve and disapprove users
function _addApprover(address _approver) public isOwner{
approvedUsers[_approver] = true;
function _removeApprovedUser(address _disapprover) public isOwner{
approvedUsers[_disapprover] = false;
//Now change rating function
function pricing(uint _rate) public{
require(approvedUsers[msg.sender],"User not in the approvers list");
//Because approvedUsers mapping returns a bool, you do not need to compare it and if it is true,
//user have access to change and if it is false user does not have access to change it
rate = _rate * (10 ** uint256(decimals()));
}

Related

Is there a way to take token out from the contract?

I created a contract and deposited some ERC20 tokens to there.
Is there a way to take to token out form the contract to my wallet?
I also want to know how to approve from the contract to other one wallet.
You need to implement a custom function in your contract that invokes the transfer() function of the token contract.
pragma solidity ^0.8;
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
contract MyContract {
address owner = address(0x123);
function withdrawToken(address tokenContract, uint256 amount) external {
// send `amount` of tokens
// from the balance of this contract
// to the `owner` address
IERC20(tokenContract).transfer(owner, amount);
}
}

Mapping lack of understanding

I read a lot about this topic and I understand it quit good.
But, the only thing I don't understand is how in functions developers use it without a function that insert the values.
example:
mapping (uint256=>address) public IdToAddress;
after they defines it I see that they are using in functions like:
function HolderOfNFT(Uint256 Id) public returns (address) {
return IdToAddress[Id];
}
How the mapping has value in the Id key that points to the right address?
Thanks a lot!!
All mapping values are empty by default.
So unless the value is set somewhere in the code, your example would return address(0) for any Id.
You can assign a mapping value the same way as you'd assign it to an array. Examples:
IdToAddress[Id] = address(0x123);
function transfer(address _recipient, uint256 _id) public {
require(IdToAddress[_id] == msg.sender, "You're not the current token owner");
IdToAddress[_id] = _recipient;
}

How to best access data from QueryRenderer in a parent component in Relay Modern?

As you can see from the picture below, I'm rendering the popover using a react-relay QueryRenderer since the request is slow, and I do not want the rest of the page to wait for events to be fetched.
My problem is that in the navigation I have a button to show/hide the popover. That button should only be rendered when events has loaded, and the button also needs to show a count of how many events there is.
So my question is how to pass events data up from QueryRenderer (popover) to a parent component (toggle button)?
My first idea was to reuse my QueryRenderer for events and pass in dataFrom={'STORE_ONLY'}, to avoid a new HTTP request and use the cache instead, but unfortunately 'STORE_ONLY' is not an option... YET...
From looking at https://github.com/relay-tools/relay-hooks/issues/5 it seems like store-only will be supported by useQuery in the future, so is that the recommended solution to go about it, or how is the recommended way? Surely facebook, and many other applications, must have had this need frequently?
You can achieve redux-like relay store with custom handlers and local schema.
I'll be guessing what your queries, components and fields might be named like so don't forget to change it to correct values
Somewhere in project's src folder create a file ClientState.client.graphql to extend your root query type with new field for client state:
// ClientState.client.graphql
type ClientState {
showToggleButton: Boolean!
eventsCount: Int
}
extend type Query {
clientState: ClientState!
}
this will allow you to wrap Toggle button with fragment like this:
fragment ToggleButton_query on Query {
clientState {
showToggleButton
eventsCount
}
}
and spread this fragment in parent query (probably AppQuery)
Then in your second query, where you'll be fetching events, add #__clientField directive, to define custom handle for that field:
query EventModal {
events #__clientField(handle: "eventsData") {
totalCount
}
}
Create EventsDataHandler for handle eventsData:
// EventsDataHandler.js
// update method will be called every time when field with `#__clientField(handle: "eventsData")` is fetched
const EventsDataHandler = {
update (store, payload) {
const record = store.get(payload.dataID)
if (!record) {
return
}
// get "events" from record
const events = record.getLinkedRecord(payload.fieldKey)
// get events count and set client state values
const eventsCount = events.getValue('totalCount')
const clientState = store.getRoot().getLinkedRecord('clientState')
clientState.setValue(eventsCount, 'eventsCount')
clientState.setValue(true, 'showToggleButton')
// link "events" to record, so the "events" field in EventModal is not undefined
record.setLinkedRecord(events, payload.handleKey)
}
}
export default EventsDataHandler
Last thing to do is to assign custom (and default) handlers to environment and create init store values:
// environment.js
import { commitLocalUpdate, ConnectionHandler, Environment, RecordSource, Store, ViewerHandler } from 'relay-runtime'
import EventsDataHandler from './EventsDataHandler'
// ...
const handlerProvider = handle => {
switch (handle) {
case 'connection':
return ConnectionHandler
case 'viewer':
return ViewerHandler
case 'eventsData':
return EventsDataHandler
default:
throw new Error(`Handler for ${handle} not found.`)
}
}
const environment = new Environment({
network,
store,
handlerProvider
})
// set init client state values
commitLocalUpdate(environment, store => {
const FIELD_KEY = 'clientState'
const TYPENAME = 'ClientState'
const dataID = `client:${FIELD_KEY}`
const record = store.create(dataID, TYPENAME)
record.setValue(false, 'showToggleButton')
// prevent relay from removing client state
environment.retain({
dataID,
variables: {},
node: { selections: [] }
})
store.getRoot().setLinkedRecord(record, FIELD_KEY)
})

Unable to get a mapping value

I'm trying to implement a small contract to upload file hashes on the blockchain along with the file description and the sender address. I've programmed this small contract :
pragma solidity^0.4.17;
contract hashes {
mapping(uint => string) descriptions;
mapping(uint => address) senderAddresses;
function uploadHash(uint _hash, string _description) public {
require(bytes(descriptions[_hash]).length == 0);
descriptions[_hash] = _description;
senderAddresses[_hash] = msg.sender;
}
function getHash(uint _hash) public returns (address, string){
return (senderAddresses[_hash], descriptions[_hash]);
}
}
I think uploadHash works as expected since when I'm uploading the same hash twice I get a revert. However when I'm trying to use getHash, I don't get any return value. The results are the same when I'm calling from remix or directly from web3.
Thanks in advance !
I believe you're missing the view modifier
function getHash(uint _hash) public view returns (address, string)
Remix will not show the res next to the input boxes unless you use the view modifier.

Signalr ConnectedUsers

i am new with asp.net mvc and signalr. I send message to all clients in my message app but i want private messaging and in this article under the title "private chat" codes are like belove:
public void SendPrivateMessage(string toUserId, string message)
{
string fromUserId = Context.ConnectionId;
var toUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == toUserId) ;
var fromUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);
if (toUser != null && fromUser!=null)
{
// send to
Clients.Client(toUserId).sendPrivateMessage(fromUserId, fromUser.UserName, message);
// send to caller user
Clients.Caller.sendPrivateMessage(toUserId, fromUser.UserName, message);
}
}
question.1: Does fromUserId have to be a number or id not a name?
question.2: Where did Connectedusers defined?because i am getting error about it.
And here is my code that sends messages to all clients:
public void Send(string alici,string name,string message)
{
Clients.All.addNewMessageToPage(name, message);
//alici:name of receiver, name:name of sender
}
Can i use alici to send message to a specific user and how?
thanks
Answer for Question 1:
toUserId must me ID that will be almost similar to GUID (Uniqueidentifier), this will help you identify each user separately even if there will be two Users with same name.
Question 2 is answered by radu-matei and thats correct by far my knowledge.
ConnectedUsers is a list of UserDetail, which holds all the connected users. Now, you can either add them in the list when they connect to the hub (so you override the OnConnected method, either you create a server function, in this case Connect, which takes a string userName as parameter.(the userName that the user sets when first entering the page)).
Now, the userId is the SignalR ConnectionId that every client recieves when connecting the hub.
public void Connect(string userName)
{
var id = Context.ConnectionId;
if (ConnectedUsers.Count(x => x.ConnectionId == id) == 0)
{
ConnectedUsers.Add(new UserDetail { ConnectionId = id, UserName = userName });
// send to caller
Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage);
// send to all except caller client
Clients.AllExcept(id).onNewUserConnected(id, userName);
}
}
This is the Connect method on the server side. Notice how a client is only added if there isn't anybody else with that ConnectionId.
Sure you can send a message to someone based on their name, but at some point you will have to deal with 2 people having the same name; it is always better to have non-repeating IDs as identifiers than names.
Hope this helps! Best of luck!

Resources