Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:

env:
FOUNDRY_PROFILE: ci
FOUNDRY_DISABLE_NIGHTLY_WARNING: true

jobs:
check:
Expand All @@ -23,7 +24,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: stable

- name: Show Forge version
run: |
Expand Down
83 changes: 83 additions & 0 deletions script/DeployAllContracts.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "forge-std/Script.sol";
import "../src/TreeNft.sol";
import "../src/token-contracts/CareToken.sol";
import "../src/token-contracts/PlanterToken.sol";
import "../src/token-contracts/LegacyToken.sol";
import "../src/OrganisationFactory.sol";

contract DeployAllContractsAtOnce is Script {
address public careTokenAddress;
address public planterTokenAddress;
address public verifierTokenAddress;
address public legacyTokenAddress;
address public treeNftAddress;

function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);

console.log("\n========== DEPLOYMENT INITIALIZED ==========");
console.log("Deployer Address: ", deployer);
console.log("Deployer ETH Balance: ", deployer.balance);
console.log("============================================\n");

vm.startBroadcast(deployerPrivateKey);
console.log(">> Step 1: Deploying ERC20 Token Contracts...");

CareToken careToken = new CareToken(deployer);
careTokenAddress = address(careToken);
console.log(" - CareToken deployed at: ", careTokenAddress);

LegacyToken legacyToken = new LegacyToken(deployer);
legacyTokenAddress = address(legacyToken);
console.log(" - LegacyToken deployed at: ", legacyTokenAddress);

console.log("\n>> Step 2: Deploying TreeNft Contract...");
TreeNft treeNft = new TreeNft(careTokenAddress, legacyTokenAddress);
treeNftAddress = address(treeNft);
console.log(" - TreeNft deployed at: ", treeNftAddress);

console.log("\n>> Step 3: Transferring Token Ownership to TreeNft...");
careToken.transferOwnership(treeNftAddress);
console.log(" - CareToken ownership transferred.");
legacyToken.transferOwnership(treeNftAddress);
console.log(" - LegacyToken ownership transferred.");

console.log("\n>> Step 4: Deploying OrganisationFactory...");
OrganisationFactory orgFactory = new OrganisationFactory(treeNftAddress);
address orgFactoryAddress = address(orgFactory);
console.log(" - OrganisationFactory deployed at:", orgFactoryAddress);

vm.stopBroadcast();

console.log("\n========== DEPLOYMENT SUMMARY ==========");
console.log("CareToken Address: ", careTokenAddress);
console.log("LegacyToken Address: ", legacyTokenAddress);
console.log("TreeNft Address: ", treeNftAddress);
console.log("OrganisationFactory: ", orgFactoryAddress);
console.log("All token ownerships successfully transferred to TreeNft.");
console.log("=========================================\n");

verifyDeployment();
}

function verifyDeployment() internal view {
console.log(">> Verifying Deployment Integrity...");

TreeNft treeNft = TreeNft(treeNftAddress);

require(address(treeNft.careTokenContract()) == careTokenAddress, "CareToken address mismatch");
require(address(treeNft.legacyToken()) == legacyTokenAddress, "LegacyToken address mismatch");

CareToken careToken = CareToken(careTokenAddress);
require(careToken.owner() == treeNftAddress, "CareToken ownership not transferred");

CareToken legacyToken = CareToken(legacyTokenAddress);
require(legacyToken.owner() == treeNftAddress, "LegacyToken ownership not transferred");

console.log("Deployment verification passed.\n");
}
}
37 changes: 37 additions & 0 deletions script/DeployOrganisationFactory.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "forge-std/Script.sol";
import "../src/TreeNft.sol";
import "../src/OrganisationFactory.sol";

contract DeployOrganisationFactory is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);
address treeNftAddress = vm.envAddress("TREE_NFT_ADDRESS");

if (treeNftAddress.code.length <= 0) revert InvalidContractAddress();

Comment on lines +14 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing import for InvalidContractAddress(); script won’t compile.

Add the errors import.

Apply:

 import "../src/OrganisationFactory.sol";
+import "../src/utils/errors.sol";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (treeNftAddress.code.length <= 0) revert InvalidContractAddress();
import "../src/OrganisationFactory.sol";
import "../src/utils/errors.sol";
🤖 Prompt for AI Agents
In script/DeployOrganisationFactory.s.sol around lines 14-15, the revert
InvalidContractAddress() is used but the error type is not imported so the
script will not compile; add an import for the InvalidContractAddress error from
your project's errors file (e.g., errors.sol) at the top of the solidity script,
ensuring the import path is correct for the repository structure, then recompile
to confirm the symbol is resolved.

console.log("\n========== DEPLOYMENT STARTED ==========");
console.log(">> Deployer Address: ", deployer);
console.log(">> Deployer Balance (wei): ", deployer.balance);
console.log(">> Linked TreeNFT Address: ", treeNftAddress);
console.log("========================================\n");

vm.startBroadcast(deployerPrivateKey);

console.log("Deploying OrganisationFactory...");
OrganisationFactory orgFactory = new OrganisationFactory(treeNftAddress);
address orgFactoryAddress = address(orgFactory);
console.log("OrganisationFactory deployed at:", orgFactoryAddress);

vm.stopBroadcast();

console.log("\n========== DEPLOYMENT SUMMARY ==========");
console.log("OrganisationFactory Address: ", orgFactoryAddress);
console.log("Linked TreeNFT Address: ", treeNftAddress);
console.log("Deployment completed successfully.");
console.log("========================================\n");
}
}
28 changes: 6 additions & 22 deletions script/DeployTreeNftContract.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@ import "forge-std/Script.sol";
import "../src/TreeNft.sol";
import "../src/token-contracts/CareToken.sol";
import "../src/token-contracts/PlanterToken.sol";
import "../src/token-contracts/VerifierToken.sol";
import "../src/token-contracts/LegacyToken.sol";

contract DeployTreeNft is Script {
address public careTokenAddress;
address public planterTokenAddress;
address public verifierTokenAddress;
address public legacyTokenAddress;
address public treeNftAddress;

Expand All @@ -29,37 +26,22 @@ contract DeployTreeNft is Script {
careTokenAddress = address(careToken);
console.log("CareToken deployed at:", careTokenAddress);

PlanterToken planterToken = new PlanterToken(deployer);
planterTokenAddress = address(planterToken);
console.log("PlanterToken deployed at:", planterTokenAddress);

VerifierToken verifierToken = new VerifierToken(deployer);
verifierTokenAddress = address(verifierToken);
console.log("VerifierToken deployed at:", verifierTokenAddress);

LegacyToken legacyToken = new LegacyToken(deployer);
legacyTokenAddress = address(legacyToken);
console.log("LegacyToken deployed at:", legacyTokenAddress);
console.log("Step 2: Deploy TreeNft contract...");

TreeNft treeNft = new TreeNft(careTokenAddress, planterTokenAddress, verifierTokenAddress, legacyTokenAddress);
TreeNft treeNft = new TreeNft(careTokenAddress, legacyTokenAddress);
treeNftAddress = address(treeNft);
console.log("TreeNft deployed at:", treeNftAddress);
console.log("Step 3: Transfer ownership to TreeNft contract...");
careToken.transferOwnership(treeNftAddress);
console.log("CareToken ownership transferred to TreeNft");
planterToken.transferOwnership(treeNftAddress);
console.log("PlanterToken ownership transferred to TreeNft");
verifierToken.transferOwnership(treeNftAddress);
console.log("VerifierToken ownership transferred to TreeNft");
legacyToken.transferOwnership(treeNftAddress);
console.log("LegacyToken ownership transferred to TreeNft");
vm.stopBroadcast();

console.log("\n=== DEPLOYMENT SUMMARY ===");
console.log("CareToken:", careTokenAddress);
console.log("PlanterToken:", planterTokenAddress);
console.log("VerifierToken:", verifierTokenAddress);
console.log("LegacyToken:", legacyTokenAddress);
console.log("TreeNft:", treeNftAddress);
console.log("All token ownerships transferred to TreeNft!");
Expand All @@ -72,12 +54,14 @@ contract DeployTreeNft is Script {
TreeNft treeNft = TreeNft(treeNftAddress);

require(address(treeNft.careTokenContract()) == careTokenAddress, "CareToken address mismatch");
require(address(treeNft.planterTokenContract()) == planterTokenAddress, "PlanterToken address mismatch");
require(address(treeNft.verifierTokenContract()) == verifierTokenAddress, "VerifierToken address mismatch");
require(address(treeNft.legacyToken()) == legacyTokenAddress, "LegacyToken address mismatch");

CareToken careToken = CareToken(careTokenAddress);
require(careToken.owner() == treeNftAddress, "CareToken ownership not transferred");
if (careToken.owner() != treeNftAddress) revert OwnershipNotTransferred();

LegacyToken legacyToken = LegacyToken(legacyTokenAddress);
if (legacyToken.owner() != treeNftAddress) revert OwnershipNotTransferred();

Comment on lines 60 to 64
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing import for custom error causes compilation failure.

OwnershipNotTransferred() is undeclared in this source unit.

Apply:

 import "../src/token-contracts/LegacyToken.sol";
+import "../src/utils/errors.sol";

Optional: stop broadcasting before view-only verification to avoid accidental txs during checks.

-        console.log("========================\n");
-        verifyDeployment();
+        console.log("========================\n");
+        vm.stopBroadcast();
+        verifyDeployment();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (careToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
PlanterToken planterToken = PlanterToken(planterTokenAddress);
if (planterToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
VerifierToken verifierToken = VerifierToken(verifierTokenAddress);
if (verifierToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
LegacyToken legacyToken = LegacyToken(legacyTokenAddress);
if (legacyToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
// --- add to imports (near other imports) ---
import "../src/token-contracts/LegacyToken.sol";
import "../src/utils/errors.sol";
// --- existing ownership checks (unchanged) ---
if (careToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
PlanterToken planterToken = PlanterToken(planterTokenAddress);
if (planterToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
VerifierToken verifierToken = VerifierToken(verifierTokenAddress);
if (verifierToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
LegacyToken legacyToken = LegacyToken(legacyTokenAddress);
if (legacyToken.owner() != treeNftAddress) revert OwnershipNotTransferred();
// --- replace before verification ---
console.log("========================\n");
vm.stopBroadcast();
verifyDeployment();
🤖 Prompt for AI Agents
In script/DeployTreeNftContract.s.sol around lines 79-89, the custom error
OwnershipNotTransferred() is not declared or imported causing compilation
failures; fix by either importing the contract/file that declares this error at
the top of the Solidity file or add a local declaration `error
OwnershipNotTransferred();` in this source unit, then keep the ownership checks
as-is; optionally, to avoid accidental transactions during view-only
verification, call vm.stopBroadcast() (or the appropriate stopBroadcast function
from the foundry runtime) before performing those read-only owner checks.

console.log("Deployment verification successful!");
}
}
25 changes: 17 additions & 8 deletions src/Organisation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,11 @@ contract Organisation {
uint256 _longitude,
string memory _species,
string memory _imageURI,
string memory _qrIpfshash,
string memory _qrPhoto,
string memory _metadata,
string[] memory photos,
string memory geoHash
string memory geoHash,
uint256 numberOfTrees
) public {
if (_latitude > 180 * 1e6) revert InvalidCoordinates();
if (_longitude > 360 * 1e6) revert InvalidCoordinates();
Expand All @@ -271,10 +273,13 @@ contract Organisation {
longitude: _longitude,
species: _species,
imageUri: _imageURI,
qrIpfsHash: _qrIpfshash,
qrPhoto: _qrPhoto,
photos: photos,
geoHash: geoHash,
status: 0
metadata: _metadata,
status: 0,
numberOfTrees: numberOfTrees,
initiator: msg.sender
});
if (checkOwnership(msg.sender)) {
s_treeProposalYesVoters[s_treePlantingProposalCounter].push(msg.sender);
Expand All @@ -285,9 +290,11 @@ contract Organisation {
proposal.longitude,
proposal.species,
proposal.imageUri,
proposal.qrIpfsHash,
proposal.qrPhoto,
proposal.metadata,
proposal.geoHash,
proposal.photos
proposal.photos,
proposal.numberOfTrees
);
}
}
Expand Down Expand Up @@ -397,9 +404,11 @@ contract Organisation {
proposal.longitude,
proposal.species,
proposal.imageUri,
proposal.qrIpfsHash,
proposal.qrPhoto,
proposal.metadata,
proposal.geoHash,
proposal.photos
proposal.photos,
proposal.numberOfTrees
);
} else if (s_treeProposalNoVoters[proposalID].length >= requiredVotes) {
proposal.status = 2;
Expand Down
4 changes: 2 additions & 2 deletions src/OrganisationFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ contract OrganisationFactory is Ownable {
contractAddress: orgAddress,
name: name,
description: description,
photoIpfsHash: photoIpfsHash,
organisationPhoto: photoIpfsHash,
owners: owners,
members: members,
ownerCount: owners.length,
Expand All @@ -123,7 +123,7 @@ contract OrganisationFactory is Ownable {
contractAddress: organisationAddress,
name: "ERROR: Unable to fetch",
description: "ERROR: Contract call failed",
photoIpfsHash: "",
organisationPhoto: "",
owners: new address[](0),
members: new address[](0),
ownerCount: 0,
Expand Down
Loading