Skip to content

Commit

Permalink
Api/contract indexer (#83)
Browse files Browse the repository at this point in the history
* created yaml file for configuring envio

* added envio indexer for querying blockchain

* updated types to bigint

* uncommented out set

* moved eas code to client

* removed EAS references from indexer

* updated contracts and scripts for new deployment
  • Loading branch information
Oba-One authored Aug 28, 2024
1 parent a8f88b7 commit 523cc05
Show file tree
Hide file tree
Showing 24 changed files with 13,091 additions and 5,223 deletions.
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

0 comments on commit 523cc05

Please sign in to comment.