pragma solidity ^0.4.0;
contract crr019_week4assignment {
// Student Account Structure
struct StudentAccount {
string Username;
address Metamask;
uint Age;
string EmailAddress;
bool BlockchainTrackEnrolled;
StudentType ClassLevel;
}
constructor() public {
}
StudentAccount [] public StudentInformation;
enum StudentType {
Freshman,
Sophomore,
Junior,
Senior,
Graduate
}
function AddStudent (string _Username, address _Metamask, uint _Age, string _EmailAddress, bool _BlockchainTrackEnrolled, StudentType _ClassLevel ) public {
// Anything inside of this function can use any of the parameters
StudentAccount memory NewStudent = StudentAccount({Username:_Username, Metamask:_Metamask, Age:_Age, Email:_EmailAddress, BlockchainTrackEnrolled:_BlockchainTrackEnrolled, Student:_ClassLevel});
}
}
Getting TypeError: Named argument does not match functions declaration.
what you should correct in your smartcontract
you must add memory after your string arguments
replace email and student with EmailAddress and ClassLevel
correct code
You have a typo when you are creating your struct instance : Use EmailAddress instead of Email.
Each property name used in your json ({}) must match names declared in the struct.
The following correction has to be done in arguments and function declaration:
instead of email you must use EmailAddress
instead of Student you must use ClassLevel
for string arguments you should use memory
The corrected segment is as follow:
function AddStudent (string memory _Username, address _Metamask, uint _Age, string memory _EmailAddress, bool _BlockchainTrackEnrolled, StudentType _ClassLevel ) public {
// Anything inside of this function can use any of the parameters
StudentAccount memory NewStudent = StudentAccount({Username:_Username, Metamask:_Metamask, Age:_Age, EmailAddress:_EmailAddress, BlockchainTrackEnrolled:_BlockchainTrackEnrolled, ClassLevel:_ClassLevel});
Inside function AddStudent correct the naming convention from email to EmailAddress. Also you can add memory after each string variable(not mandatory).
Naming should be done properly.
Corrected code :
pragma solidity 0.6.12;
contract crr019_week4assignment {
// Student Account Structure
struct StudentAccount {
string Username;
address Metamask;
uint Age;
string EmailAddress;
bool BlockchainTrackEnrolled;
StudentType ClassLevel;
}
constructor() public { }
StudentAccount [] public StudentInformation;
enum StudentType {
Freshman,
Sophomore,
Junior,
Senior,
Graduate
}
function AddStudent (string memory _Username, address _Metamask, uint _Age, string memory _EmailAddress, bool _BlockchainTrackEnrolled, StudentType _ClassLevel ) public {
// Anything inside of this function can use any of the parameters
StudentAccount memory NewStudent = StudentAccount({Username:_Username, Metamask:_Metamask, Age:_Age, EmailAddress:_EmailAddress, BlockchainTrackEnrolled:_BlockchainTrackEnrolled, ClassLevel:_ClassLevel});
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract crr019_week4assignment {
// Student Account Structure
struct StudentAccount {
string Username;
address Metamask;
uint Age;
string EmailAddress;
bool BlockchainTrackEnrolled;
StudentType ClassLevel;
}
constructor() {}
StudentAccount [] public StudentInformation;
enum StudentType {
Freshman,
Sophomore,
Junior,
Senior,
Graduate
}
function addStudent (string memory _Username, address _Metamask, uint _Age, string memory _EmailAddress, bool _BlockchainTrackEnrolled, StudentType _Classlevel) public {
StudentAccount memory NewStudent = StudentAccount(_Username, _Metamask, _Age, _EmailAddress, _BlockchainTrackEnrolled, _Classlevel);
StudentInformation.push(NewStudent);
}
}
Related
I am trying to create a function that returns an array of strings. Sadly instead of returning an array that has N number of elements of type string, it just appends all my string values to the first and only element in the array.
pragma solidity ^0.8.7;
contract Store is Ownable {
struct Product {
string name;
uint32 quantity;
bool exists;
}
uint64 private productId;
mapping(uint => Product) private products;
constructor() {
productId = 1;
}
function addProduct(string calldata name, uint32 quantity) public onlyOwner
require(quantity > 0, "Quantity cannot be negative integer");
productId = productId + 1;
products[productId] = Product(name, quantity, true);
}
function listProducts() external view returns (string[] memory){
string[] memory productsInfo = new string[](productId);
if(productId < 1){
return productsInfo;
}
for(uint i = 0; i < productId; i++){
string memory info = products[i + 1].name;
productsInfo[i] = info;
}
return productsInfo;
}
}
If I add products a, b, c. The json result from colling listProducts() looks like this:
{
"0": "string[]: a,b,c"
}
the contract is working.
Solidity display the elements in array with commas between them.
Array return start with "0" string[].
Hope it will help
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
contract Store{
struct Product {
string name;
uint32 quantity;
bool exists;
}
address private Owner;
uint64 private productId;
mapping(uint => Product) private products;
constructor() {
productId = 1;
Owner = msg.sender;
}
modifier onlyOwner{
require(msg.sender == Owner, "Fail! only admin can access this
function!");
_;
}
function addProduct(string calldata _name, uint32 _quantity) public
onlyOwner{
Product memory _strucObj;
_strucObj.name = _name;
_strucObj.quantity = _quantity;
products[productId -1] = _strucObj;
productId++;
}
function listProducts() external view returns (string[] memory){
string[] memory productsInfo = new string[](productId);
if(productId < 1){
return productsInfo;
}
//dash symbol used for concatenation
string memory dash = "-";
for(uint i = 0; i < productId; i++){
string memory info = products[i].name;
productsInfo[i] = info;
}
return productsInfo;
}
function CheckProductsByIndex(uint index) public view returns(string memory name)
{
string[] memory productsInfo = new string[](productId);
for(uint i = 0; i < productId; i++)
{
string memory _toArray = products[i].name;
productsInfo[i] = _toArray;
}
return productsInfo[index];
}
}
How to make a new contract using remix with a function in which I want to get the user details from my already deployed contract on the blockchain
Please be elaborate on the answer with some code as I am very new to solidity.
//deployed contract
struct User {
address wallet_address;
string userId;
string first_name;
string last_name;
}
mapping(address => User) users;
mapping(string => address) walletAccount;
mapping(address => uint) public balanceOf;
User public newUser;
uint public length;
address public owner;
constructor() public {
owner = msg.sender;
}
event userCreated (
address wallet_address,
string userId,
string first_name,
string last_name
);
function createNewUser(address userAcc, string memory _id, string memory firstName, string memory lastName) public {
User storage user = users[userAcc];
users[userAcc] = User(userAcc,_id,firstName,lastName);
}
function getUser(address _userAddress, string memory _lastName) public view returns (address, string memory, string memory, string memory) {
User memory user = users[_userAddress];
return (users[_userAddress].wallet_address, users[_userAddress].userId, users[_userAddress].first_name, users[_userAddress].last_name);
}
I'm using Drizzle and when ever I call createInvestorToken on this contract I get Error: Returned error: VM Exception while processing transaction: revert . Not sure how to debug this. It succeeds in the test, but it won't succeed otherwise.
If I remove the allTokens.push(new InvestmentToken(_name,_symbol,initalSupply,_cost)); it works.
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract InvestmentToken is ERC20{
string public name;
string public symbol;
uint256 public decimals = 0;
uint256 public INITIAL_SUPPLY;
uint256 public cost;
address public parent;
constructor(string memory _name, string memory _symbol, uint256 initalSupply, uint256 _cost) public {
name = _name;
symbol = _symbol;
INITIAL_SUPPLY = initalSupply;
cost=_cost;
parent = msg.sender;
_mint(msg.sender, INITIAL_SUPPLY);
}
function buyToken(address receiver, uint256 amount) public {
if (msg.sender != parent) {
revert("You may only buy through the DPAC token");
}
uint256 tokensLeft = balanceOf(msg.sender);
if (tokensLeft >= amount/cost){
_transfer(msg.sender,receiver, amount/cost);
} else {
revert("There are no more tokens");
}
}
}
contract TheParentToken {
string public name = "DPAC_Token";
string public symbol = "DPAC";
uint256 public decimals = 0;
uint256 public INITIAL_SUPPLY = 10000;
uint256 public numberOfTokens = 0;
mapping(address => bool) public tokenWhiteList;
InvestmentToken[] public allTokens;
address public administrator;
constructor() public {
administrator = msg.sender;
allTokens.push(new InvestmentToken("A","B",1000,1));
allTokens.push(new InvestmentToken("B","C",1000,1));
numberOfTokens = allTokens.length;
}
function createInvestorToken(string memory _name, string memory _symbol, uint256 initalSupply, uint256 _cost) public {
allTokens.push(new InvestmentToken(_name,_symbol,initalSupply,_cost));
numberOfTokens = allTokens.length;
}
function addTokenToWhiteList(address newToken) public {
if(msg.sender != administrator){
revert("Not Admin");
}
tokenWhiteList[newToken]=true;
}
function removeTokenFromWhiteList(address newToken) public {
if(msg.sender != administrator){
revert("Not Admin");
}
tokenWhiteList[newToken]=false;
}
}
In this case the token was hitting the gas limit, and the error wasn't being displayed as the Gas Issue.
I think because it was creating a token the error is suppressed.
I am creating a contract for identification person, and I need to verify if there are some contracts with the same address, email, or phone number.
Example:
contract Person {
//date of create
uint public dateCreate;
//name of person
string public name;
//variables to be validates
string public email;
string public phone;
// constructor
function Person(string _name, string _email, string _phone) public {
name = _name;
email = _email;
phone = _phone;
owner = msg.sender;
}
}
I have the option to save the address contract in a mapping with the key email or phone.
contract RegisterPerson {
//save the contract address person using the key of the email
mapping(bytes32=>address) public addressEmail;
}
There is this solution, but I believe it's not the better because the mapping it will be very big and the contract expensive.
Does anybody know another solution?
You shouldn't be using a contract to represent an object like you're attempting to do here. Not only is it very costly as contract deployments are usually much more expensive than transactions, but you also can't guarantee uniqueness.
You should use a struct to represent the individual.
contract PersonStorage {
struct Person {
uint dateCreate;
string name;
string email;
string phone;
}
mapping(bytes32 => Person) persons;
function addPerson(string _name, string _email, string _phone) public {
Person memory person;
person.name = _name;
person.email = _email;
person.phone = _phone;
persons[keccak256(person.email)] = person;
}
...
}
Now, your contract is data storage for all Persons. You can deploy this version and pass the contract address to whatever contracts need access to it. You'll also have all your data centralized in case you need to allow multiple business logic contracts to use it or if you need to upgrade your business contract.
EDIT - I should note that if this is in its own contract, you'll have to change from string to bytes32. You can't send strings between contracts.
Why is it not allowed to have separate constructor definitions in TypeScript?
To have e.g. two constructors, I need to write my code like this.
constructor(id: number)
constructor(id: number, name?: string, surname?: string, email?: string) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}
Thereby I need to put ? after the parameters that are not required in the first constructor.
Why can't I write it like this?
constructor(id: number) {
this.id = id;
}
constructor(id: number, name: string, surname: string, email: string) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}
So that for both constructors all parameters are mandatory.
Moreover, if I need to have an empty constructor things get even weirder, since I need to mark every parameter with a ?.
constructor()
constructor(id?: number, name?: string, surname?: string, email?: string) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}
Why does TypeScript differs from common languages like C# or Python here?
I would expect it to work like this.
constructor() {
}
constructor(id: number, name: string, surname: string, email: string) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}
So you can pass none parameter or must pass all parameters.
Because your constructor implementation is called by all your overload constructors. (Technically, at runtime there's only one constructor function that gets called with the various overload argument signatures.)
Imagine it like this:
overload_constructor(id:string) {
implementation_constructor(id);
}
implementation_constructor(id:string, name?:string, age?:number) {
// ...
}
Thinking of it this way, overload_constructor could not call implementation_constructor unless name and age are optional.
Also see Basarat's answer, the implementation isn't exposed for public usage by the type checker (though at runtime it's the "real" constructor used in JS). If you want to only allow (), (id), or (id, name, surname, email) as the only valid call signatures you would do it like this:
constructor()
constructor(id: number)
constructor(id: number, name: string, surname: string, email: string)
constructor(id?: number, name?: string, surname?: string, email?: string) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}
Note that in the implementation all parameters are optional, but that signature is not exposed when compiling and you can only use these these calls:
new Foo()
new Foo(1)
new Foo(1, "a", "b", "c")
Not, for example:
new Foo(1, "a")
The last function overload is only used in the implementation and not available publicly. This is shown below:
class Foo{
constructor()
constructor(id?: number) {
}
}
const foo1 = new Foo();
const foo2 = new Foo(123); // Error! : not public
If you want id:number to be available publically ofcourse you can add another overload:
class Foo{
constructor()
constructor(id: number)
constructor(id?: number) {
}
}
const foo1 = new Foo();
const foo2 = new Foo(123); // Okay
const foo3 = new Foo('hello'); // Error: Does not match any public overload
The reason is that TypeScript tries not to do fancy code generation for function overloading (traditional languages do this using name mangling e.g. C++)
So you can pass none parameter or must pass parameters.
Actually you can make the final overload optional but none of the public ones as optional. Consider the following example:
class Foo{
constructor(id: number, name:string)
constructor(name:string)
constructor(idOrName?: number|string, name?:string) {
}
}
const foo1 = new Foo('name'); // Okay
const foo2 = new Foo(123); // Error: you must provide a name if you use the id overload
const foo3 = new Foo(123,'name'); // Okay
You can use Builder pattern to solve this. Even in C# or Python, it quickly becomes a better approach as the number of constructor arguments grows.
class Foo {
constructor(public id: number, public name: string, public surname: string, public email: string) {
}
static Builder = class {
id: number = NaN;
name: string = null;
surname: string = null;
email: string = null;
Builder() {
}
build(): Foo {
return new Foo(this.id, this.name, this.surname, this.email);
}
}
}
If you use static methods to implement overload contructors, see.
export class User implements IUser {
constructor(
private _id: string,
private _name: string,
private _email: string,
) {}
static New(jsonUser:string){
return new User(
JSON.parse(jsonUser).id,
JSON.parse(jsonUser).name,
JSON.parse(jsonUser).email)
}
}