Deploying smart contract with arrays in the constructor - arrays

I'm quite new with solidity and, while I was checking more complex contracts, I found this type of constructor and I was wondering on how I should write the strings while deploying it.
constructor(
address[] memory payees,
uint256[] memory shares,
address[] memory addresses,
uint256 swapAmount
) ERC20("Token", "TOKEN") PaymentSplitter(payees, shares) {
require(addresses.length == 5, "Count of Addresses must be 5");
treasuryPool = addresses[0];
distributionPool = addresses[1];
marketingPool = addresses[2];
expensePool = addresses[3];
cashoutPool = addresses[4];
for (uint256 i = 0; i < 5; i++)
_isExcludedFromFee[addresses[i]] = true;
require(expensePool != address(0) && distributionPool != address(0), "FUTUR & REWARD ADDRESS CANNOT BE ZERO");
I tried different things but all failed.

The input field next to Deploy button in Remix IDE is where we put our data.
Following would be a valid input to call your constructor/deploy your contract.
["0x0000000000000000000000000000000000000001"],[0,1,2],["0x0000000000000000000000000000000000000002"],3

Related

Compare two arrays in memory in Solidity and a return a "not in" result

I have a large contract and I am in the process of splitting it out into two. The goal is to have the functions that are common (and will be used by many other contracts) to be separated out for efficiency.
One of these functions compares items in arrays "ownedSymbols" and "targetAssets". It produces a list "sellSymbols" if any item in "ownedSymbols" is not in "targetAssets".
The below code works fine while "sellSymbols" is stored as a string. As this function will become common, I need it to run in memory so the results aren't confused by calls from different contracts.
pragma solidity >0.8.0;
contract compareArrays {
string[] public ownedSymbols = ["A","B","C"];
string[] public targetAssets = ["A","B"];
string[] sellSymbols;
event sellListEvent(string[]);
function sellList(string[] memory _ownedSymbols, string[] memory _targetAssetsList) internal {
sellSymbols = _ownedSymbols;
for (uint256 i = 0; i < _targetAssetsList.length; i++) {
for (uint256 x = 0; x < sellSymbols.length; x++) {
if (
keccak256(abi.encodePacked((sellSymbols[x]))) ==
keccak256(abi.encodePacked((_targetAssetsList[i])))
) {
if (x < sellSymbols.length) {
sellSymbols[x] = sellSymbols[sellSymbols.length - 1];
sellSymbols.pop();
} else {
delete sellSymbols;
}
}
}
}
emit sellListEvent(sellSymbols);
}
function runSellList() public {
sellList(ownedSymbols,targetAssets);
}
}
Ideally the function would run with "string[] memory sellSymbols", however this kicks back an error.
pragma solidity >0.8.0;
contract compareArrays {
string[] public ownedSymbols = ["A","B","C"];
string[] public targetAssets = ["A","B"];
event sellListEvent(string[]);
function sellList(string[] memory _ownedSymbols, string[] memory _targetAssetsList) internal {
string[] memory sellSymbols = _ownedSymbols;
for (uint256 i = 0; i < _targetAssetsList.length; i++) {
for (uint256 x = 0; x < sellSymbols.length; x++) {
if (
keccak256(abi.encodePacked((sellSymbols[x]))) ==
keccak256(abi.encodePacked((_targetAssetsList[i])))
) {
if (x < sellSymbols.length) {
sellSymbols[x] = sellSymbols[sellSymbols.length - 1];
sellSymbols.pop();
} else {
delete sellSymbols;
}
}
}
}
emit sellListEvent(sellSymbols);
}
function runSellList() public {
sellList(ownedSymbols,targetAssets);
}
}
The error:
TypeError: Member "pop" is not available in string memory[] memory outside of storage.
--> contracts/sellSymbols.sol:20:25:
|
20 | sellSymbols.pop();
| ^^^^^^^^^^^^^^^
Two questions from me:
Is there a way to do this in memory so that the function can be common (i.e. used by multiple contracts at the same time)?
Is there a better way? The below is expensive to run, but it is the only way I have been able to achieve it.
One final comment - I know this would be much easier/cheaper to run off chain. That is not something I am willing to consider as I want this project to be decentralized.
If you want to keep the existing system, the best solution is described here: https://stackoverflow.com/a/49054593/11628256
if (x < sellSymbols.length) {
sellSymbols[x] = sellSymbols[sellSymbols.length - 1];
delete sellSymbols[myArray.length - 1];
sellSymbols.length--;
} else {
delete sellSymbols;
}
If all you care about is the presence or absence of a particular asset (and not enumerating through them), what you're going to want to do to really reduce gas costs is something called "lazy evaluation." Lazy evaluation is when instead of computing all results at once (like increasing all balances by 50% by iterating over an array), you modify the getters so that their return value reflects the operation (such as multiplying an internal variable by 50% and multiplying the original result of getBalance by that variable).
So, if this is the case, what you want to do is use the following function instead:
function except(string _item, mapping(string => bool) _ownedSymbols, mapping(string => bool) _targetAssets) internal returns (bool) {
return _ownedSymbols[_item] && !_targetAssets[_item];
}
<pet peeve>
Finally, I know you say you want this to be decentralized, but I really do feel the urge to say this. If this is a system that doesn't need to be decentralized, don't decentralize it! Decentralization is great for projects that other people rely on - for example, DNS or any sort of token.
From your variable names, it seems that this is probably some sort of system similar to a trading bot. Therefore, the incentive is on you to keep it running, as you are the one that gets the benefits. None of the problems that decentralization solves (censorship, conflict of interest, etc...) apply to your program, as the person running it is incentivized to keep it running and keep a copy of the program. It's cheaper for the user running it to not have security they don't need. You don't need a bank-grade vault to store a $1 bill!
</pet peeve>

Solidity function with arrays gives overflow error

I have the same code without an array and it just works.
But In this one if i enter amount anything more than 0.001 ether it gives an overflow error.
I tried Other functions called in this one with errored values and they don't give an error.
CheckPairValue() and CheckSellPrice() works.
Code is to check my Wallet's worth in pancakeswap
Idk what's wrong.
Any help is appretiated.
Also Contract is verified on bscscan.
Contract
function GetSellValue(address[] memory TokenAddress, uint[] memory Amount)public view returns(uint256[] memory){
uint[] memory Value = new uint[](TokenAddress.length);
for(uint i = 0; i < TokenAddress.length; i++){
address Pair = CheckPairValue(TokenAddress[i], Amount[i] * 2);
address[] memory path;
if(Pair != PairAddresses[0]){
path = new address[](3);
path[0] = TokenAddress[i];
path[1] = Pair;
path[2] = PairAddresses[0];
}
else
{
path = new address[](2);
path[0] = TokenAddress[i];
path[1] = PairAddresses[0];
}
Value[i] = CheckSellPrice(Amount[i],path);
}
return Value;
}
0.001 ether input works , anything higher doesn't
I still don't know why remix errored like this.
But i've written a js code to call the contract and it works.

How to find duplicate entry in Solidity array

I'm writing a function that is supposed to receive an array of uint's and I want to make a requirement that none of the elements in the array be the same and that all of the elements in the array be part of the pre-selected elements to belong in an array. So far I have:
function vote(uint[] memory proposals) external
{
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote.");
require(!sender.voted, "Already voted.");
mapping(uint => bool) duplicateVotes;
require(!duplicateVotes, "Cannot vote for a proposal more than once.");
sender.voted = true;
sender.vote = proposals;
proposals[proposals].voteCount += sender.weight;
}
But I get an error:
The data location must be "storage", "memory" or "calldata" for variable, but none was given.
But I think this error is just a symptom of a larger problem. Can anyone help me figure out a solution to this problem?
I think u want to achieve that same person does not vote twice but the way you are doing is computationally expensive and this will cost too much gas. Instead, crate a mapping to keep track if voter has voted before:
mapping(address=>bool) peopleWhoVoted;
also you want to keep array of voters
address[] public listOfVoters;
So in your vote function, make sure that caller of this function-msg.sender is not in the peopleWhoVoted mapping
function vote(pass argument) public {
// msg.sender is globally available, it is function caller
require(!peopleWhoVoted[msg.sender],"this caller already voted")
// now u are sure that this caller did not vote before
// so u can add the function caller to the array
listOfVoters.push(msg.sender)
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
contract findDupli {
uint[] public arr = [2,3,4,8,1,7,8];
function funFind() public view returns(uint) {
uint temp;
for(uint i = 0; i < arr.length; i++) {
temp = arr[i];
for(uint j = 0; j < arr.length; j++) {
if((j != i) && (temp == arr[j])) {
return temp;
}
}
}
}
}

How do I efficiently replace a storage array in Solidity?

I have the following function in Solidity which takes as arguments 2 arrays, an array of shareholder addresses and an array of their stakes. I'm keeping an array of shareholders in storage, together with a map to their stakes.
If the updated array is the same size, it's simple, just overwrite each position with the new values. If they are different sizes however, I first go through the entire array and delete each element, and then insert the new ones. I feel this is not very efficient and it could be done better.
PS: I am a complete beginner to Solidity and this is my first contract, so please feel free to let me know if I'm doing anything stupid or inefficiently.
Thanks !
function setShareholders(address[] _shareholders, uint256[] _stakes) public onlyCEO {
require(_shareholders.length > 0);
require(_shareholders.length == _stakes.length);
uint256 accummulator = 0;
for(uint8 x = 0; x < _stakes.length; x++){
require(_addressNotNull(_shareholders[x]));
require(_stakes[x] > 0 && _stakes[x] <= 100);
accummulator = SafeMath.add(accummulator, _stakes[x]);
}
if(accummulator == 100){ // stakes need to add up to 100%
_setShareholders(_shareholders, _stakes);
}
}
function _setShareholders(address[] _shareholders, uint256[] _stakes) private {
if(_shareholders.length == shareholders.length){
for(uint8 x = 0; x < shareholders.length; x++) {
shareholders[x] = _shareholders[x];
shareholderToStake[_shareholders[x]] = _stakes[x];
}
}
else {
for(x = 0; x < shareholders.length; x++) {
delete shareholders[x];
shareholders.length--;
delete shareholderToStake[shareholders[x]];
}
for(x = 0; x < _shareholders.length; x++) {
shareholders.push(_shareholders[x]);
shareholderToStake[_shareholders[x]] = _stakes[x];
}
}
}
In theory, this would work...unfortunately in solidity, managing arrays is a costly nightmare. Doing any array manipulation, on not just one but 2 arrays, is not recommended at all.
You could keep your array of shareholders...but from there, I'd recommend creating a mapping of address->structure. This way you can loop through your mapped structure and contain all necessary data within that.
So something like this for your refactor:
address[] public shareholders;
struct ShareHolder {
uint stake;
// ...other awesome data here
}
mapping (address => ShareHolder) public shareholderData;
This way, you have your shareholders list. And you can directly access a shareholder with shareholderData[<SHAREHOLDER ADDRESS>].

Compare NDIS_STRING case-insensitively at IRQL = DISPATCH_LEVEL?

I have a NDIS 6 filter driver. And I need to compare two NDIS_STRING in a case-insensitive manner at IRQL = DISPATCH_LEVEL. I know the RtlEqualUnicodeString function can compare strings in a case-insensitive manner. But it's only callable at PASSIVE_LEVEL.
So I have to write my own function using the basic memory copy way. And I found my function is not well functioned, because some of my users complain that this function returns FALSE when it's supposed to return TRUE. So there should be some bugs in my code. But I didn't find it by myself.
BOOLEAN
NPF_EqualAdapterName(
PNDIS_STRING s1,
PNDIS_STRING s2
)
{
int i;
BOOLEAN bResult;
TRACE_ENTER();
if (s1->Length != s2->Length)
{
IF_LOUD(DbgPrint("NPF_EqualAdapterName: length not the same, s1->Length = %d, s2->Length = %d\n", s1->Length, s2->Length);)
TRACE_EXIT();
return FALSE;
}
for (i = 0; i < s2->Length / 2; i ++)
{
if (s1->Buffer[i] >= L'A' && s1->Buffer[i] <= L'Z')
{
s1->Buffer[i] += (L'a' - L'A');
}
if (s2->Buffer[i] >= L'A' && s2->Buffer[i] <= L'Z')
{
s2->Buffer[i] += (L'a' - L'A');
}
}
bResult = RtlEqualMemory(s1->Buffer, s2->Buffer, s2->Length);
IF_LOUD(DbgPrint("NPF_EqualAdapterName: bResult = %d, s1 = %ws, s2 = %ws\n", i, bResult, s1->Buffer, s2->Buffer);)
TRACE_EXIT();
return bResult;
}
The entire code is here: https://github.com/nmap/npcap/blob/master/packetWin7/npf/npf/Openclos.c, if you want to know it.
So my question is simply, is there any bugs in the above code? Thanks!
UPDATE:
The adapter names (e.g., s1 and s2) are some GUIDs like {1CC605D7-B674-440B-9D58-3F68E0529B54}. They can be upper-case or lower-case. So they are definitely English.
An idea of using an index or key would be storing the names in GUID structure instead of strings. I noticed that Windows has provided RtlStringFromGUID and RtlGUIDFromString functions. However, these two functions also only work at IRQL = PASSIVE_LEVEL.
And much of my code just runs under DISPATCH_LEVEL. So I'm afraid storing in GUID is not a good idea.

Resources