Retrieve nested mapping in Solidity - mapping

Pls, help to figure out how to retrieve the nested mapping in the Solidity.
string tokenURI;
uint256 tokenId;
There is Solidity mapping:
mapping(uint256 => mapping(address => string);
How to get all tokenURI based on address? I need to print them out using Python.
I created loop but it doesn't work:
uint256[] public tokens; // numbers 0,1,2 etc
address[] public clients; // addresses
string[] public uris;
function getNftUri() public {
for (uint256 i = 0; i < tokens.length; i++){
uint256 t = tokens[i];
for (uint256 j = 0; j < clients.length; j++){
address client = clients[j];
if (client == msg.sender){
uris.push(nftCollection2[t][client]);
}
}
}
//return uris;
}

Soldity mappings are not iterable, so you'll need to duplicate the values in an array to be able to get all values by a key.
mapping(address => mapping(uint256 => string)) tokenURIs;
// this way you can query `tokenURIsByAddress[owner]` to get all token URIs by an address
// `push()` to this array to add items
// as well as remove items from the array
mapping(address => string[]) tokenURIsByAddress;
You can also make use of some existing library for iterable mappings that does exactly the same thing as described in my code comment above.

Related

solidity add only unique string values to address mapped array

Im trying to map an string array to addresses, to store data for each address seperateluy.
the function below works only if a regular string is also parallely initiated.
my objective is to store the list of stocks for each address .
the code below works only when you also add the data on to simple string array.
what is the issue?
pragma solidity >=0.5.0 <0.9.0;
contract test{
string[] stocks;
// mapping address to a string array
mapping(address=>string[]) public portfolio;
// function to add string to mapped array only if its not present already
function addIfNotPresent(string memory tick) public {
address user=msg.sender;
uint arrayLength = stocks.length;
if(arrayLength == 0){
portfolio[user].push(tick);
//
// this code dosent work if the line below is removed
//
stocks.push(tick);
}else{
bool found=false;
for (uint i=0; i<arrayLength; i++) {
if (keccak256(abi.encodePacked(portfolio[user][i])) == keccak256(abi.encodePacked(tick))) {
found = true;
break;
}
}
if(!found){
portfolio[user].push(tick);
stocks.push(tick);
}
}
}
}```

UnimplementedFeatureError: Copying of type struct {ContractName.StructName} memory[] memory to storage not yet supported

・I want to create the lottery contract that user can buy some lottery numbers.
And, if the lottery was finished, I want to initialize it to create a new lottery.
That's why we implemented it this way.
lotChances = new LotChance[](0);
But, I faced this is error ...πŸ‘‡
UnimplementedFeatureError: Copying of type struct Lottery.LotChance memory[] memory to storage not yet supported.
Minimal example:
contract Lottery {
// Lot Structs
struct LotChance {
address payable userAddress;
uint256 ids;
}
LotChance[] public lotChances;
function getResult() public onlyOwner {
luckyPerson.transfer(address(this).balance);
lotteryId++;
lotChances = new LotChance[](0);
}
}
Please advise me😌
For reset an array and set his values to default you can use delete keyword in Solidity. In your case, you must to change your getResult() function in this way:
function getResult() public onlyOwner {
luckyPerson.transfer(address(this).balance);
lotteryId++;
delete lotChances;
}
You can see an example of smart contract code, here following:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
contract Lottery {
address owner;
constructor() {
owner = msg.sender;
}
// Lot Structs
struct LotChance {
address payable userAddress;
uint256 ids;
}
modifier onlyOwner() {
require(msg.sender == owner, "You aren't smart contract owner!");
_;
}
LotChance[] public lotChances;
function getResult(address _luckyPerson) public onlyOwner {
uint lotteryId = 0;
payable(_luckyPerson).transfer(address(this).balance);
lotteryId++;
// I reset array length about to '0'
delete lotChances;
}
function partecipateToLottery(uint _id) public {
lotChances.push(LotChance(payable(msg.sender), _id));
}
function getLengthArray() external view returns(uint) {
return lotChances.length;
}
}

How to create a Grid without POJO (dynamic columns)?

The question was asked here: https://vaadin.com/forum/thread/18095407/how-to-create-a-grid-without-binder
However the vaadin's forum closed so i want to continue it here.
On Vaadin 14, Any recommendation on the best way to implement grid with dynamic varying number of columns. Using column Index (1,2,3...) is not a good choice for me. Let say I have a simple Json file (only 1 level: key-value) to map to a grid and this Json has an unknown list of properties.
which approach is better in term of performance ?:
[Option 1]
class Data {
private Map<String, Object> values = new HashMap<>();
public void set(String key, Object val) {
values.put(key, val);
}
public Object get(String key) {
return values.get(key);
}
}
Grid<Data> myGrid = new Grid<>();
[Option 2]
public class GridDynamicValueProvider implements ValueProvider<GridDynamicRow, Object> {
private int columnIndex;
public GridDynamicValueProvider(int columnIndex) {
this.columnIndex = columnIndex;
}
#Override
public Object apply(GridDynamicRow dynamicRow) {
return dynamicRow.getValue(columnIndex);
}
}
public class GridDynamicRow {
private List<Object> values = new ArrayList<>();
public void addValue(String value) {
values.add(value);
}
public Object getValue(int columnIndex) {
return values.get(columnIndex);
}
}
The SerializablePredicate of Vaadin accepts both function references and Lambdas, thus it is possible to use non-POJO data types with Grid and Binder in Vaadin, although that is a bit unconventional. The key ingredients are:
Grid<Map<String, Integer>> grid = new Grid<>();
...
grid.addColumn(map -> map.get("column")).setHeader("Column");
You can also wrap the Map in custom class if you have need to protect the internals.
class Data {
private Map<String, Object> values = new HashMap<>();
public void set(String key, Object val) {
values.put(key, val);
}
public Object get(String key) {
return values.get(key);
}
}
Grid<Data> myGrid = new Grid<>();
As for the performance, essentially, you're comparing between using a List where you fetch by index versus a HashMap where you fetch by key. Here's a related question: ArrayList .get faster than HashMap .get?
You can use also ArrayList as Grid's type if you can index the columns with a number.
The both approaches allow generating Grid's with varying dynamic number of columns, for example if you read the data directly from a file or have raw data backend queries.

Expected Primary Expression (Solidity)

I am creating a simple smart contract, however, I am getting an error on my last function ("ViewNotes") stating that the compiler was "Expected Primary Expression"? Can I not check the value at a mapping (of address => string) against the value 0 ?
My code:
pragma solidity ^0.4.4;
contract Logistics{
address public owner;
mapping(address => string) notes;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
constructor(address genesis) public {
owner = genesis;
}
function sign(string signedNote) public onlyOwner{
notes[owner] = signedNote; //gaurenteed that msg.sender == owner
}
function transferOwnership(address nuOwner) onlyOwner {
owner = nuOwner;
}
function viewNotes(address participant) public returns(string){ // signed note on success nothing on fail
if(notes[participant] !== 0){
return (notes(participant));
}
}
}
There are a couple issues. The primary issue is that you misspelled !=. (You have an extra equals sign. !== is an operator in JavaScript, but not in Solidity.)
Once you fix that, you'll find that you can't compare a string to the number 0. You probably want to check the string's length? You'll need to cast to bytes to do that:
function viewNotes(address participant) public returns (string) {
if (bytes(notes[participant]).length != 0) {
return notes[participant];
}
}
That said, I believe this is probably equivalent to just:
function viewNotes(address participant) public returns (string) {
return notes[participant];
}
And you could instead just make notes public:
mapping(address => string) public notes;
That way, Solidity will generate a getter function for you, and people can just call notes(addr), making viewNotes redundant.
Fixing up a couple other warnings, getting rid of the modifier in favor of a direct ownership check, and assigning initial ownership to the deployer, here's my take on the contract:
pragma solidity ^0.4.24;
contract Logistics{
address public owner = msg.sender;
mapping(address => string) public notes;
function sign(string note) public {
require(msg.sender == owner);
notes[owner] = note;
}
function transferOwnership(address newOwner) public {
require(msg.sender == owner);
owner = newOwner;
}
}

Enforce that a variable can be assigned only once

Let's say I have this code inside a class:
String _str;
String get str => _str;
void set(String s) {
assert(_str == null);
_str = s;
}
How could I ensure that only the setter and getter have access to _str? This would be to prevent that anything inside the same class would be unable to bypass the condition.
There is no way. In Dart privacy is per library. Everything within one library can read/write everything else within that library.
I would go for
String __str;
String get str => __str;
void set(String s) {
assert(__str == null);
__str = s;
}
and just never access members that start with two underscores except from within the associated getter/setter pairs.
I do this sometimes when I want a private field with private getter setter like
String __str;
String get _str => __str;
void _set(String s) {
assert(_str == null);
__str = s;
}
A weird workaround would be to create a class in another library like
class StringProperty {
String _str;
String get value => _str;
void set value(String s) {
assert(_str == null);
_str = s;
}
}
and then use it in your library like
final StringProperty str = new StringProperty();
You can then access the value then like
str.value = 'abc';
print(str.value);
and in no other way.

Resources