1

I'm developing a crowdfunding DApp that constantly needs to access the contract variables through function calls in order to retrieve them.

The getDeployedCampaigns function returns an array of deployed campaign's addresses. They then get passed down to a map function in order to create a react component with the corresponding address on it.

In the ideal scenario I would like to be able to also retrieve and use the campaignTitle variable inside the campaign contract but I'm having lots of trouble in finding a way of doing so without breaking the whole rendering program.

This is how the code is currently working

import { Card, Button } from "semantic-ui-react";
import factory from "../ethereum/factory";
import Layout from "../components/Layout";
import { Link } from "../routes";

class CampaignIndex extends Component {
  static async getInitialProps() {
    const campaigns = await factory.methods.getDeployedCampaigns().call();

    return { campaigns };
  }
  renderCampaigns() {
    const items = this.props.campaigns.map((address) => {
      return {
        header: address,
        description: (
          <Link route={`/campaigns/${address}`}>
            <a>View Campaign</a>
          </Link>
        ),
        fluid: true,
      };
    });
    return <Card.Group items={items} />;
  }
  render() {
    return (
      <Layout>
        <div>
          <h3>Open Campaigns</h3>
          <Link route="/campaigns/new">
            <a>
              <Button
                floated="right"
                content="Create Campaign"
                icon="add circle"
                primary
              />
            </a>
          </Link>
          {this.renderCampaigns()}
        </div>
      </Layout>
    );
  }
}

export default CampaignIndex;

And this is what I am trying to do but is not working at all

import { Card, Button } from 'semantic-ui-react';
import factory from '../ethereum/factory';
import Layout from '../components/Layout';
import { Link } from '../routes';
import Campaign from '../ethereum/campaign';

class CampaignIndex extends Component {
  static async getInitialProps() {
    const campaigns = await factory.methods.getDeployedCampaigns().call();

    const campaignInfo = Promise.all(
      campaigns.map(async (address) => {
        const campaign = Campaign(address);
        const title = await campaign.methods.campaignTitle().call();

        return {
          header: title,
          meta: address,
          description: (
            <Link route={`/campaigns/${address}`}>
              <a>View Campaign</a>
            </Link>
          ),
          fluid: true,
        };
      })
    );

    return { campaignInfo };
  }
  renderCampaigns() {
    const items = this.props.campaignInfo;
    return <Card.Group items={items} />;
  }
  render() {
    return (
      <Layout>
        <div>
          <h3>Open Campaigns</h3>
          <Link route="/campaigns/new">
            <a>
              <Button
                floated="right"
                content="Create Campaign"
                icon="add circle"
                primary
              />
            </a>
          </Link>
          {this.renderCampaigns()}
        </div>
      </Layout>
    );
  }
}

export default CampaignIndex;

And the Smart Contract for you to see


contract CampaignFactory {
    address[] public deployedCampaigns;

    function createCampaign(uint minimum, string title, string description) public {
        address newCampaign = new Campaign(minimum, msg.sender, title, description);
        deployedCampaigns.push(newCampaign);
    }

    function getDeployedCampaigns() public view returns (address[]) {
        return deployedCampaigns;
    }
}

contract Campaign {
    struct Request {
        string description;
        uint value;
        address recipient;
        bool complete;
        uint approvalCount;
        mapping(address => bool) approvals;
    }

    Request[] public requests;
    address public manager;
    uint public minimumContribution;
    string public campaignTitle;
    string public campaignDescription;
    mapping(address => bool) public approvers;
    uint public approversCount;

    modifier restricted() {
        require(msg.sender == manager);
        _;
    }

    function Campaign(uint minimum, address creator, string givenTitle, string givenDescription) public {
        manager = creator;
        minimumContribution = minimum;
        campaignTitle = givenTitle;
        campaignDescription = givenDescription;

        
    }

    function contribute() public payable {
        require(msg.value > minimumContribution);

        approvers[msg.sender] = true;
        approversCount++;
    }

    function createRequest(string description, uint value, address recipient) public restricted {
        Request memory newRequest = Request({
           description: description,
           value: value,
           recipient: recipient,
           complete: false,
           approvalCount: 0
        });

        requests.push(newRequest);
    }

    function approveRequest(uint index) public {
        Request storage request = requests[index];

        require(approvers[msg.sender]);
        require(!request.approvals[msg.sender]);

        request.approvals[msg.sender] = true;
        request.approvalCount++;
    }

    function finalizeRequest(uint index) public restricted {
        Request storage request = requests[index];

        require(request.approvalCount > (approversCount / 2));
        require(!request.complete);

        request.recipient.transfer(request.value);
        request.complete = true;
    }
    
    function getSummary() public view returns (
      uint, uint, uint, uint, address
      ) {
        return (
          minimumContribution,
          this.balance,
          requests.length,
          approversCount,
          manager
        );
    }
    
    function getRequestsCount() public view returns (uint) {
        return requests.length;
    }
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
MontesJP
  • 11
  • 1

2 Answers2

0

In the factory contract, you are returning an array of items directly, Which means you are using a newer version of solidity. However, in Campaign contract, you are using function Campaign which is meant to be used as a constructor in early versions of solidity. If you are using newer version of solidity, you initialize the contract with the constructor keyword, since you do not use constructor you are not assigning value to title.

Instead of function Campaign use constructor

constructor(uint minimum, address creator, string givenTitle, string givenDescription) {
        manager = creator;
        minimumContribution = minimum;
        campaignTitle = givenTitle;
        campaignDescription = givenDescription;
        
    }
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
0

I think it is because you didn't retrieve the CampaignName in the getSummary function.

TylerH
  • 20,799
  • 66
  • 75
  • 101
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 20 '22 at 03:56