Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api/contract indexer #83

Merged
merged 9 commits into from
Aug 28, 2024
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"deploy:arbitrum": "pnpm --filter 'contracts' run deploy:arbitrum --network arbitrum"
},
"dependencies": {
"@ethereum-attestation-service/eas-sdk": "^2.5.0",
"dotenv": "16.4.5",
"ethers": "^6.13.2",
"viem": "^2.19.6"
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const WORK_SCHEMA_UID =
"0x9341009d07b8de3eb72b96ac42246c549f3e32636cb31a75961fbee6db44a0eb";
export const WORK_APPROVAL_SCHEMA_UID =
"0x019249c30ec1d02ae41abb3fbbeeb56b9bbb2261cf94191fac73089308aa662a";
export const GARDEN_ASSESSMENT_SCHEMA_UID =
"0x7433e24287be826b49e5eb28cd52192823e542521c94084a691e67e5cc7e8176";
85 changes: 85 additions & 0 deletions packages/app/src/modules/eas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { EAS } from "@ethereum-attestation-service/eas-sdk";

const eas = new EAS("0xbD75f629A22Dc1ceD33dDA0b68c546A1c035c458");

const getWorkAttestation = async (workUID: string): Promise<Work> => {
const attestation = await eas.getAttestation(workUID);
const data = JSON.parse(attestation.data);

return {
id: workUID,
ownerAddress: attestation.attester,
garden_id: attestation.recipient,
action_id: data.filter((d: any) => d.name === "actionUID")[0].value.value!,
title: data.filter((d: any) => d.name === "title")[0].value.value!,
feedback: data.filter((d: any) => d.name === "feedback")[0].value.value!,
metadata: data.filter((d: any) => d.name === "metadata")[0].value.value!,
media: data.filter((d: any) => d.name === "media")[0].value.value!,
createdAt: attestation.time,
};
};

const getWorkApprovalAttestation = async (
workApprovalUID: string
): Promise<WorkApproval> => {
const attestation = await eas.getAttestation(workApprovalUID);
const data = JSON.parse(attestation.data);

return {
id: workApprovalUID,
approverAddress: attestation.attester,
action_id: data.filter((d: any) => d.name === "actionUID")[0].value.value!,
work_id: data.filter((d: any) => d.name === "workUID")[0].value.value!,
approved: data.filter((d: any) => d.name === "approved")[0].value.value!,
feedback: data.filter((d: any) => d.name === "feedback")[0].value.value!,
createdAt: attestation.time,
};
};

const getGardenAssessmentAttestation = async (
gardenAssessmentUID: string
): Promise<GardenAssessment> => {
const attestation = await eas.getAttestation(gardenAssessmentUID);
const data = JSON.parse(attestation.data);

return {
id: gardenAssessmentUID,
authorAddress: attestation.attester,
garden_id: attestation.recipient,
soilMoisturePercentage: data.filter(
(d: any) => d.name === "soilMoisturePercentage"
)[0].value.value!,
carbonTonStock: data.filter((d: any) => d.name === "carbonTonStock")[0]
.value.value!,
carbonTonPotential: data.filter(
(d: any) => d.name === "carbonTonPotential"
)[0].value.value!,
gardenSquareMeters: data.filter(
(d: any) => d.name === "gardenSquareMeters"
)[0].value.value!,
biome: data.filter((d: any) => d.name === "biome")[0].value.value!,
remoteReportCID: data.filter((d: any) => d.name === "remoteReportPDF")[0]
.value.value!,
speciesRegistryCID: data.filter(
(d: any) => d.name === "speciesRegistryJSON"
)[0].value.value!,
polygonCoordinates: data.filter(
(d: any) => d.name === "polygonCoordinates"
)[0].value.value!,
treeGenusesObserved: data.filter(
(d: any) => d.name === "treeGenusesObserved"
)[0].value.value!,
weedGenusesObserved: data.filter(
(d: any) => d.name === "weedGenusesObserved"
)[0].value.value!,
issues: data.filter((d: any) => d.name === "issues")[0].value.value!,
tags: data.filter((d: any) => d.name === "tags")[0].value.value!,
createdAt: attestation.time,
};
};

export {
getWorkAttestation,
getWorkApprovalAttestation,
getGardenAssessmentAttestation,
};
5 changes: 5 additions & 0 deletions packages/app/src/types/greengoods.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare interface Garden {}
declare interface GardenAssessment {}
declare interface Action {}
declare interface Work {}
declare interface WorkApproval {}
21 changes: 14 additions & 7 deletions packages/contracts/script/DeployGardenToken.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,18 @@ contract DeployGardenToken is Script {
console.log("GardenToken deployed at:", token);

// Mint a garden for Rio Claro, São Paulo
address[] memory gardeners = new address[](1);
address[] memory gardenOperators = new address[](1);
address[] memory gardeners = new address[](4);
address[] memory gardenOperators = new address[](4);

gardeners[0] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e; // afo-wefa.eth
gardeners[1] = 0xAcD59e854adf632d2322404198624F757C868C97; // groweco.eth
gardeners[2] = 0x29e6cbF2450F86006292D10A3cF791955600a457; // marcin
gardeners[3] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e; // [email protected]
gardenOperators[0] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e; // afo-wefa.eth
gardenOperators[1] = 0xAcD59e854adf632d2322404198624F757C868C97; // groweco.eth
gardenOperators[2] = 0x29e6cbF2450F86006292D10A3cF791955600a457; // marcin
gardenOperators[3] = 0x2aa64E6d80390F5C017F0313cB908051BE2FD35e; // [email protected]

gardenAccount = gardenToken.mintGarden(communityToken, "Root Planet", gardeners, gardenOperators);

vm.stopBroadcast();
Expand Down Expand Up @@ -124,11 +131,11 @@ contract DeployGardenToken is Script {
string.concat(
'src/GardenAccount.sol:GardenAccount --constructor-args $(cast abi-encode "constructor(address,address,address,address)" ',
Strings.toHexString(erc4337EntryPoint),
" ",
", ",
Strings.toHexString(multicallForwarder),
" ",
", ",
Strings.toHexString(TOKENBOUND_REGISTRY),
" ",
", ",
Strings.toHexString(guardian),
")\n"
)
Expand All @@ -140,7 +147,7 @@ contract DeployGardenToken is Script {
string.concat(
'src/AccountProxy.sol:AccountProxy --constructor-args $(cast abi-encode "constructor(address,address)" ',
Strings.toHexString(guardian),
" ",
", ",
Strings.toHexString(implementation),
")\n"
)
Expand All @@ -151,7 +158,7 @@ contract DeployGardenToken is Script {
string.concat(
'src/GardenToken.sol:GardenToken --constructor-args $(cast abi-encode "constructor(address)" ',
Strings.toHexString(implementation),
"",
", ",
Strings.toHexString(gardenAccount),
")\n"
)
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/script/DeployResolvers.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ contract DeployResolvers is Script {
block.chainid,
predictedWorkResolverAddress,
string.concat(
'src/resolvers/Work.sol:WorkResolver --constructor-args $(cast abi-encode "constructor(address,address)" ',
'src/resolvers/Work.sol:WorkResolver --constructor-args $(cast abi-encode "constructor(address,address)", ',
Strings.toHexString(eas),
", ",
Strings.toHexString(ACTION_REGISTRY),
Expand Down
31 changes: 31 additions & 0 deletions packages/contracts/src/accounts/Garden.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ contract GardenAccount is AccountV3Upgradable, Initializable {
/// @param newName The new name of the garden.
event NameUpdated(address indexed updater, string newName);

/// @notice Emitted when the garden description is updated.
/// @param updater The address of the entity that updated the description.
/// @param newDescription The new description of the garden.
event DescriptionUpdated(address indexed updater, string newDescription);

/// @notice Emitted when a new gardener is added.
/// @param updater The address of the entity that added the gardener.
/// @param gardener The address of the added gardener.
Expand All @@ -41,6 +46,9 @@ contract GardenAccount is AccountV3Upgradable, Initializable {
/// @notice The name of the garden.
string public name;

/// @notice The description of the garden.
string public description;

/// @notice Mapping of gardener addresses to their status.
mapping(address gardener => bool isGardener) public gardeners;

Expand All @@ -64,16 +72,22 @@ contract GardenAccount is AccountV3Upgradable, Initializable {
/// @dev This function must be called after the contract is deployed.
/// @param _communityToken The address of the community token associated with the garden.
/// @param _name The name of the garden.
/// @param _description The description of the garden.
/// @param _gardeners An array of addresses representing the initial gardeners.
/// @param _gardenOperators An array of addresses representing the initial garden operators.
function initialize(
address _communityToken,
string calldata _name,
string calldata _description,
address[] calldata _gardeners,
address[] calldata _gardenOperators
) external initializer {
communityToken = _communityToken;
name = _name;
description = _description;

gardeners[_msgSender()] = true;
gardenOperators[_msgSender()] = true;

for (uint256 i = 0; i < _gardeners.length; i++) {
gardeners[_gardeners[i]] = true;
Expand All @@ -86,6 +100,10 @@ contract GardenAccount is AccountV3Upgradable, Initializable {
}

emit NameUpdated(_msgSender(), _name);
emit DescriptionUpdated(_msgSender(), _description);

emit GardenerAdded(_msgSender(), _msgSender());
emit GardenOperatorAdded(_msgSender(), _msgSender());
}

/// @notice Updates the name of the garden.
Expand All @@ -101,6 +119,19 @@ contract GardenAccount is AccountV3Upgradable, Initializable {
emit NameUpdated(_msgSender(), _name);
}

/// @notice Updates the description of the garden.
/// @dev Only callable by a valid signer of the contract.
/// @param _description The new description of the garden.
function updateDescription(string memory _description) external {
if (_isValidSigner(_msgSender(), "")) {
revert NotGardenOwner();
}

description = _description;

emit DescriptionUpdated(_msgSender(), _description);
}

/// @notice Adds a new gardener to the garden.
/// @dev Only callable by a valid signer of the contract.
/// @param gardener The address of the gardener to add.
Expand Down
47 changes: 36 additions & 11 deletions packages/contracts/src/registries/Action.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,39 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {

/// @notice Emitted when a new action is registered.
/// @param owner The address of the action owner.
/// @param actionUID The unique identifier of the action.
/// @param action The details of the registered action.
event ActionRegistered(address indexed owner, Action indexed action);
event ActionRegistered(address indexed owner, uint256 indexed actionUID, Action indexed action);

/// @notice Emitted when an action is updated.
/// @notice Emitted when an existing action is start time is updated.
/// @param owner The address of the action owner.
/// @param action The updated details of the action.
event ActionUpdated(address indexed owner, Action indexed action);
/// @param actionUID The unique identifier of the action.
/// @param startTime The new start time of the action.
event ActionStartTimeUpdated(address indexed owner, uint256 indexed actionUID, uint256 indexed startTime);

/// @notice Emitted when an existing action is end time is updated.
/// @param owner The address of the action owner.
/// @param actionUID The unique identifier of the action.
/// @param endTime The new end time of the action.
event ActionEndTimeUpdated(address indexed owner, uint256 indexed actionUID, uint256 indexed endTime);

/// @notice Emitted when an existing action is title is updated.
/// @param owner The address of the action owner.
/// @param actionUID The unique identifier of the action.
/// @param title The new title of the action.
event ActionTitleUpdated(address indexed owner, uint256 indexed actionUID, string indexed title);

/// @notice Emitted when an existing action is instructions are updated.
/// @param owner The address of the action owner.
/// @param actionUID The unique identifier of the action.
/// @param instructions The new instructions of the action.
event ActionInstructionsUpdated(address indexed owner, uint256 indexed actionUID, string indexed instructions);

/// @notice Emitted when an existing action is media is updated.
/// @param owner The address of the action owner.
/// @param actionUID The unique identifier of the action.
/// @param media The new media URLs of the action.
event ActionMediaUpdated(address indexed owner, uint256 indexed actionUID, string[] indexed media);

uint256 private _nextActionUID;

Expand Down Expand Up @@ -79,7 +105,7 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {
actionToOwner[actionUID] = _msgSender();
idToAction[actionUID] = Action(_startTime, _endTime, _title, _instructions, _capitals, _media);

emit ActionRegistered(_msgSender(), idToAction[actionUID]);
emit ActionRegistered(_msgSender(), actionUID, idToAction[actionUID]);
}

/// @notice Updates the start time of an existing action.
Expand All @@ -88,7 +114,7 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {
function updateActionStartTime(uint256 actionUID, uint256 _startTime) external onlyActionOwner(actionUID) {
idToAction[actionUID].startTime = _startTime;

emit ActionUpdated(actionToOwner[actionUID], idToAction[actionUID]);
emit ActionStartTimeUpdated(actionToOwner[actionUID], actionUID, _startTime);
}

/// @notice Updates the end time of an existing action.
Expand All @@ -97,16 +123,15 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {
function updateActionEndTime(uint256 actionUID, uint256 _endTime) external onlyActionOwner(actionUID) {
idToAction[actionUID].endTime = _endTime;

emit ActionUpdated(actionToOwner[actionUID], idToAction[actionUID]);
}
emit ActionEndTimeUpdated(actionToOwner[actionUID], actionUID, _endTime);}

/// @notice Updates the title of an existing action.
/// @param actionUID The unique identifier of the action to update.
/// @param _title The new title for the action.
function updateActionTitle(uint256 actionUID, string calldata _title) external onlyActionOwner(actionUID) {
idToAction[actionUID].title = _title;

emit ActionUpdated(actionToOwner[actionUID], idToAction[actionUID]);
emit ActionTitleUpdated(actionToOwner[actionUID], actionUID, _title);
}

/// @notice Updates the instructions for an existing action.
Expand All @@ -118,7 +143,7 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {
) external onlyActionOwner(actionUID) {
idToAction[actionUID].instructions = _instructions;

emit ActionUpdated(actionToOwner[actionUID], idToAction[actionUID]);
emit ActionInstructionsUpdated(actionToOwner[actionUID], actionUID, _instructions);
}

/// @notice Updates the media associated with an existing action.
Expand All @@ -127,7 +152,7 @@ contract ActionRegistry is UUPSUpgradeable, OwnableUpgradeable {
function updateActionMedia(uint256 actionUID, string[] memory _media) external onlyActionOwner(actionUID) {
idToAction[actionUID].media = _media;

emit ActionUpdated(actionToOwner[actionUID], idToAction[actionUID]);
emit ActionMediaUpdated(actionToOwner[actionUID], actionUID, _media);
}

/// @dev Authorizes an upgrade to the contract's implementation.
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/src/tokens/Garden.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract GardenToken is ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @param owner The owner of the minted Garden token.
/// @param tokenId The unique identifier of the minted Garden token.
/// @param name The name of the Garden associated with the minted token.
event GardenMinted(address indexed owner, uint256 indexed tokenId, string name);
event GardenMinted(address indexed owner, uint256 indexed tokenId, address indexed account);

/// @custom:oz-upgrades-unsafe-allow constructor
/// @param gardenAccountImplementation The address of the Garden account implementation.
Expand Down Expand Up @@ -56,7 +56,7 @@ contract GardenToken is ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {

GardenAccount(payable(gardenAccount)).initialize(communityToken, name, gardeners, gardenOperators);

emit GardenMinted(_msgSender(), tokenId, name);
emit GardenMinted(_msgSender(), tokenId, gardenAccount);

return gardenAccount;
}
Expand Down
1 change: 0 additions & 1 deletion packages/eas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"@ethereum-attestation-service/eas-sdk": "^2.5.0",
"commander": "^12.1.0",
"zod": "^3.23.8"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/indexer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# To create or update a token visit https://envio.dev/app/api-tokens
ENVIO_API_TOKEN="<YOUR-API-TOKEN>"
Loading