This is my first Solidity project.
I'm trying to create a kind of supply chain, more than anything just practice code.
I came across a problem that I couldn't solve or find the solution online.
Problem: I want to get the user ID and save it in each function so it would look like...
function Customer() public {
checked = Process.Received;
status = Process.NotPaid;
//userid = Process.< THE ID >
}
I tried with this ...
function getStruct() public
view
returns (string, uint)
{
return (User);
}
But keeps on asking me to have the data located in memory. Which I tried but won't work for me.
Full code:
pragma solidity ^0.5.1;
contract SupplyChain {
enum Process {
Unknown,
Checked,
Received,
Paid,
NotPaid
}
Process public status;
Process public checked;
Process public userid;
address user;
struct User {
uint _id;
string _firstName;
string _lastName;
}
constructor() public {
status = Process.Unknown;
user = tx.origin;
}
function addUser(
uint256 id,
string memory _firstName,
string memory _lastName
) public{
}
// NOT FINISHED NEED TO RETURN USER ID TO PRINT IN TRACKERS.
function getStruct() public
view
returns (string, uint)
{
return (User);
}
function Factory() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function TransportOne() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function Deposit() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function TransportTwo() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function Customer() public {
checked = Process.Received;
status = Process.NotPaid;
// print userid
}
}
There is no print in solidity, you can try to use events for logging.
If you just want to debug, you can try Remix IDE.
Related
from solidity:
contracts/3_Ballot.sol:33:37: TypeError: Named argument does not match function declaration.
Request memory newRequest = Request({
^ (Relevant source part starts here and spans across multiple lines).
I get this error every time. What should i do for the solve it?
pragma solidity ^0.4.17;
contract Campaign {
struct Request {
string description;
uint value;
address recipient;
bool complete;
}
Request[] public requests;
address public manager;
uint public minimumContirbution;
address[] public approvers;
modifier restricted() {
require (msg.sender == manager);
_;
}
function Campaign (uint minimum) public {
manager = msg.sender;
minimumContirbution = minimum;
}
function contribute () public payable {
require(msg.value > minimumContirbution);
approvers.push(msg.sender);
}
function createRequest(string description, uint value, address recipient) restricted public {
Request memory newRequest = Request({
description: description,
value: value,
restricted: restricted,
complete: false
});
requests.push(newRequest);
}
}
You can define the Request struct in this way and push it into requests array:
function createRequest(string description, uint value, address recipient) restricted public {
Request memory newRequest = Request(description, value, recipient, false);
requests.push(newRequest);
}
In this way, you can add the struct into your array and can retrieve with all parameters setted previously.
Because you're are using wrong argument(restricted) inside you Request type
try this:
Request memory newRequest = Request({
descritption: descritpion,
value: value,
recipient: recipient,
complete: false
});
I'm running into a problem with solidity with structures containing arrays, can you help me see what I'm missing?Any help would be greatly appreciated!
struct Info {
uint a;
uint256 b;
uint[] data;
}
mapping(address => Info) infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() public {
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
}
I am a little confused as to what you require, but first solution I have provided modifies your Smart Contract such that mapping object infos and the getter function is both private (available only in the Contract defined).
contract test{
struct Info {
uint a;
uint b;
uint[] data;
}
mapping(address => Info) private infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() private view{
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
} }
Second solution is to add something called 'require' in the getter function so that only the person who deploys the Smart Contract can view the array index. The constructor function assigns the person who deploys the contract as the 'owner'.
contract test{
struct Info {
uint a;
uint b;
uint[] data;
}
address owner;
constructor() {
owner = msg.sender;
}
mapping(address => Info) infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() public view{
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
require(owner == msg.sender, 'you cannot read this data, you are not the owner!');
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
}
}
Let me know if I have misunderstood your question.
I'm starting to learn OOP and I know it's hard to build good, quality, testable code and I'm afraid to make some architectural mistake and the beginning because it's harder to refactor later.
Currently, I'm working on Laravel and I need a component (a small part of a program) to calculate online advertising statistics (CPM, EPC and so on) uisng cronjob. For this purpose, I need to collect data from the database, calculate statistic(s) and store it to related table. This need to be run through CLI using cronjob. Calculation of stats should be done if possible by SQL, but it not always can be done with current architecture.
So I need to create some reusable component which can be easily extended with new stat calculation logic, either with just fetch already calculated logic from DB and store it or fetch, calculate and store to DB. And to have ability for futuhre to use it easily in any part of application not just by CLI.
To run it from CLI I'm using Laravel command with scheduling:
class StatsComamnd extends Command
{
protected $signature = 'project:calculatestats {statName}';
public function __construct(StatsService $statsService){
parent::__construct();
$this->statsService = $statsService;
}
public function handle() {
$method = $this->argument('statName');
if(!method_exists($this, $method)) {
$this->error('Invalid stat name provided!');
}
$this->{$method}();
}
public function networkOffers():void {
$this->stastService->setStatsHandler(app(OffersNetworkStatsHandler::class))->handle();
}
public function networkOffersCpm():void{
app(OffersNetworkCpmHandler::class)->handle();
}
public function networkOffersEpc:void{
app(OffersNetworkEpcHandler::class)->handle();
}
public function networkSurveys():void{
app(SurveysNetworkHandler::class)->handle();
}
public function networkSurveysCpm():void{
app(SurveysNetrworkCpmHandler::class)->handle();
}
public function networkSurveysEpc:void{
app(SurveysNetworkEpcHandler::class)->handle();
}
//...other handlers, like countryOffersCpm, toolSpecificOffersCpm and so on
}
SurveysNetrworkCpmStatsHandler:
/** This handle responsible of collectiong, calculating and storing network wide survey CPMs. We can't calculate CPM inside DB, so here we are going to use CpmCalculator */
class SurveysNetrworkCpmStatsHandler implements StatsHandlerInterface {
private $surveyImpressionsRepo;
private $statsRepo;
private $vcPointRepo;
private $calculator;
public function __construct(
SurveyImpressionRepositoryInterface $surveyImpressionRepository,
SurveyStatsRepositoryInterface $statsRepository,
VcPointRepositoryInterface $vcPointRepository,
CpmCalculator $calculator
){
$this->surveyImpressionsRepo = $surveyImpressionRepository;
$this->calculator = $calculator;
$this->vcPointRepo = $vcPointRepository;
$this->statsRepo = $statsRepository;
}
public function handle() {
$stats = [];
list($impressions, $conversions) = $this->fetchStatisticData();
foreach ($impressions as $impression) {
$sid = $impression->survey_id;
$conversion = $conversions->first(function($conversion) use ($sid) {
return $conversion->survey_id === $sid;
});
if(!isset($conversion)) {
continue;
}
$stat = new \SurveyNetworkCpmStat();
$stat->offer_id = $impression->offer_id;
$stat->survey_id = $sid;
$stat->mobile_cpm = $this->calculator->setConversionCount($conversion->conversions_count_mobile)->setImpressionsCount($impression->unique_impressions_count_mobile)->setPayoutSum($conversion->payout_sum_mobile)->calculate();
$stat->desktop_cpm = $this->calculator->setConversionCount($conversion->conversions_count_desktop)->setImpressionsCount($impression->unique_impressions_count_desktop)->setPayoutSum($conversion->payout_sum_desktop)->calculate();
$stat[] = $stat->toArray();
}
$this->store($stats)
}
private function fetchStatisticData(){
$impressions = $this->surveyImpressionsRepo->getImpressionsForNetworkCpm();
$conversions = $this->vcPointRepo->getConversionsForSurveyNetworkCpm();
return [$impressions, $conversions];
}
private function store($stst): bool{
$this->statsRepo->insert()
}
}
SurveysNetrworkStatsHandler:
/** This handle responsible of collectiong, calculating and storing all network wide survey stats.*/
class SurveysNetrworkStatsHandler implements StatsHandlerInterface {
private $cpmHandler;
private $epcHandler;
private $statsRepo;
public function __construct(
SurveysNetrworkCpmStatsHandler $cpmHandler,
SurveysNetrworkEpcStatsHandler $epcHandler,
SurveyStatsRepositoryInterface $statsRepository
){
$this->cpmHandler = $cpmHandler;
$this->epcHandler = $epcHandler;
$this->statsRepo = $statsRepository;
}
public function handle() {
$this->cpmHandler->handle();
$this->epcHandler->handle();
}
}
OffersNetrworkCpmStatsHandler:
etrworkCpmStatsHandler:
/** This handle responsible of collectiong, calculating and storing network wide offers CPMs. We can calculate CPM inside DB, so here do not need any Calculator */
class OffersNetrworkCpmStatsHandler implements StatsHandlerInterface {
private $surveyImpressionsRepo;
private $statsRepo;
public function __construct(
SurveyImpressionRepositoryInterface $surveyImpressionRepository,
SurveyStatsRepositoryInterface $statsRepository
){
$this->surveyImpressionsRepo = $surveyImpressionRepository;
$this->statsRepo = $statsRepository;
}
public function handle() {
$stats = [];
$stats = $this->fetchStatisticData();
$this->store($stats)
}
private function fetchStatisticData(){
return $this->surveyImpressionsRepo->getCpm();
}
private function store($stst): bool{
$this->statsRepo->insert()
}
}
CpmCalculator:
/** Class NetworkCpmCalculator. This object responsible for calculation of CPM. Formula to calculate cpm is payout_sum/(impressions_count/1000) */
class NetworkCpmCalculator implements StatsCalculatorInterface {
private $payoutSum = 0;
private $impressionsCount = 0;
private $conversionsCount = 0;
public function setPayoutSum(float $payoutSum = null):self{
$this->payoutSum = $payoutSum;
return $this;
}
public function setImpressionsCount(int $impressionsCount = null):self{
$this->impressionsCount = $impressionsCount;
return $this;
}
public function setConversionCount(int $conversionsCount = null):self{
$this->conversionsCount = $conversionsCount;
return $this;
}
public function calculate():int{
if(!$this->validate()) {
return null;
}
return $this->payoutSum/($this->impressionsCount/1000);
}
//validation here
}
I remove all validation logic here and interfaces to reduca amount of code.
Can anyone suggest any improvements, maybe I can use some patterns here? Thanks for any suggestions.
Let's start with my solidity code :
pragma solidity ^0.4.18;
contract Voting {
address mainAddress;
bytes32[] candidateNames;
mapping(bytes32 => uint) candidateVotes;
mapping(bytes32 => bytes32) candidatesDetails;
address[] voters;
function Voting() public {
mainAddress = msg.sender;
}
modifier isMainAddress {
if (msg.sender == mainAddress) {
_;
}
}
function getAllCandidates() public view returns (bytes32[]) {
return candidateNames;
}
function setCandidate(bytes32 newCandidate) isMainAddress public {
candidateNames.push(newCandidate);
}
function setVote(bytes32 candidate) public {
require(validVoters());
candidateVotes[candidate] = candidateVotes[candidate] + 1;
voters.push(msg.sender);
}
function getVote(bytes32 candidate) public view returns (uint) {
return candidateVotes[candidate];
}
function setDescrption(bytes32 candidateName, bytes32 candidatesDesc) isMainAddress public {
candidatesDetails[candidateName] = candidatesDesc;
}
function getDescription(bytes32 candidateName) public view returns (bytes32){
return candidatesDetails[candidateName];
}
function getCurrentAddress() public view returns (address) {
return msg.sender;
}
function validVoters() public view returns (bool) {
for(uint i = 0; i < voters.length ; i++){
if (voters[i] == msg.sender) {
return false;
}
}
return true;
}
}
The functions : Voting(), getAllCandidates(), setCandidate(), getVote(), setDescription(), getDescription(), getCurrentAddress() works fine when called multiple times. So, I guess we can ignore them for now.
The function setVote() runs fine the first time it executes ie. when a person votes for once. The problem arises when the same person tries to vote the second time. It gives the following error :
This might be a beginners mistake but I have been trying to fix this for 2 days straight and now I really need help.
Also,
I use Remix - browser based IDE to run/check my solidity code.
I use Ganache for test accounts.
Thanks.
The function in question:
function setVote(bytes32 candidate) public {
require(validVoters());
candidateVotes[candidate] = candidateVotes[candidate] + 1;
voters.push(msg.sender);
}
Note that validVoters() must return true for this function to succeed. If it returns false, the require will fail and revert the transaction. Also note that at the end of the function, msg.sender is added to the array voters.
Let's take a look at validVoters():
function validVoters() public view returns (bool) {
for(uint i = 0; i < voters.length ; i++){
if (voters[i] == msg.sender) {
return false;
}
}
return true;
}
This function returns false if msg.sender is in voters, which we know will be the case after the account has voted once.
So the second time through, validVoters() returns false, which causes require(validVoters()) in setVote() to revert the transaction.
I got some troubles making a method that transfer money from object to another
which is mainly was to make a class that simulates a tester class that do the following
public class BankAccountTest
{
public void main()
{
// Create an account with an opening balance of 5000 AED for Mr. Said
BankAccount acc1 = new BankAccount("Said", 5000);
acc1.withdraw(1000);
acc1.printAccountInfo(); // Should display on the screen: "Said's blanace is 4000"
// Create an accoutn with an initial balance of ZERO for Mr. Shady
BankAccount acc2 = new BankAccount("Shady");
acc2.deposit(2000);
// Transfer 3000 from acc2 to acc1. If successful, the method returns 0, otherwise -1
int code = acc2.transfer(acc1, 3000);
if(code !=0) {
System.out.println("Insufficient Fund!");
}
System.our.println(acc1.balance() );
System.our.println(acc2.balance() );
}
}
So here is my code
public class BankAccount
{
public int balance;
private int deposite;
private int withdraw;
private String name;
public BankAccount(String name)
{ balance = 5000;
}
public BankAccount(String nameName, int balance)
{
name = nameName;
this.balance = balance;
deposite = 0;
withdraw = 0;
}
public void DepostieMoney (int deposite)
{ this.balance = balance + deposite;}
public void WithdrawMoney(int withdraw)
{ this.balance = balance - withdraw;
}
public void printAccountInfo()
{
System.out.println(this.name + "'s balance is " + balance);
}
public void TransferMoney(BankAccount that , int balance)
{ this.balance= this.balance - balance;
}
}
what I couldn't able to figure is how to make the following method transfer the items of the first object to the second object
public void TransferMoney(BankAccount that , int balance)
{ this.balance= this.balance - balance;
So how actually I can specify methods for specific object ?.
edited withdrawMoney method
public void withdrawMoney(int balance)
{if ( balance <= this.balance)
this.balance = this.balance - balance;
else
{System.out.println("insfufficient funds");}
}
First of all, the Java coding style suggests:
Methods should be verbs, in mixed case with the first letter
lowercase, with the first letter of each internal word capitalized (e.g run(); runFast(); getBackground(); )
Now, for you question, you're trying to transfer the money from the one account to the other, so the method called on one object should call the second object in order to complete the transaction.
public void transferMoney(BankAccount that , int balance)
{
//sanity check here
if (this == that || that == null)
return;
If (withdrawMoney(balance)) {
that.depositeMoney(balance);
}
}
As you see I choose not to use the variables directly but through the methods. The reason is that the logic around the method could be more than simply updating the variable, for example you may want to print the action. This way you only need to update once the code in your method, the transferMoney method will remain the same.