diff --git a/README.md b/README.md index b6f9120..3ce3091 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,9 @@ The `EndaomentAdmin` contract creates the Roles necessary to execute the oversig Several "getter" functions are also available to allow for querying of current role status or holder. +### `EndaomentAdminStorage.sol` +To prevent an attacker from deploying their own EndaomentAdmin contract and representing themselves as the EndaomentAdmin, both `FundFactory` and `OrgFactory` use `EndaomentAdminStorage` to allow `Fund` and `Org` contracts to keep a record of the current and correct `EndaomentAdmin` contract for overseeing actions. + ### `Administratable.sol` Provides an interface containing key modifiers for administering the `FundFactory` and `OrgFactory` that reference the `EndaomentAdmin` contract. diff --git a/contracts/Administratable.sol b/contracts/Administratable.sol index f5f22e1..9261137 100644 --- a/contracts/Administratable.sol +++ b/contracts/Administratable.sol @@ -4,8 +4,11 @@ pragma solidity ^0.6.10; import "./EndaomentAdmin.sol"; +//ADMINISTRATABLE /** - * @dev Provides two modifiers allowing contracts administered + * @title Administratable + * @author rheeger + * @notice Provides two modifiers allowing contracts administered * by the EndaomentAdmin contract to properly restrict method calls * based on the a given role. Also provides a utility function for * validating string input arguments. @@ -33,18 +36,20 @@ contract Administratable { * @notice onlyAdminOrRole checks that the caller is either the Admin or the provided role. * @param adminContractAddress supplied EndaomentAdmin address * @param role The role to require unless the caller is the owner. Permitted - * roles are admin (0), accountant (2), and reviewer (3). + * roles are ADMIN (6), ACCOUNTANT (2), REVIEWER (3), FUND_FACTORY (4) and ORG_FACTORY(5). */ modifier onlyAdminOrRole(address adminContractAddress, IEndaomentAdmin.Role role) { _onlyAdminOrRole(adminContractAddress, role); _; } - - function _onlyAdminOrRole(address adminContractAddress, IEndaomentAdmin.Role role) - private - view - { + /** + * @notice _onlyAdminOrRole checks that the caller is either the Admin or the provided role. + * @param adminContractAddress supplied EndaomentAdmin address + * @param role The role to require unless the caller is the owner. Permitted + * roles are ADMIN (6), ACCOUNTANT (2), REVIEWER (3), FUND_FACTORY (4) and ORG_FACTORY(5). + */ + function _onlyAdminOrRole(address adminContractAddress, IEndaomentAdmin.Role role) private view { require( adminContractAddress != address(0), "Administratable: Admin must not be the zero address" @@ -83,22 +88,32 @@ contract Administratable { } } } - - // TODO(rheeger): write docs in audit-l05 - modifier onlyAddressOrAdminOrRole(address allowedAddress, address adminContractAddress, IEndaomentAdmin.Role role) { + + /** + * @notice Checks that the caller is either a provided adress, admin or role. + * @param allowedAddress An exempt address provided that shall be allowed to proceed. + * @param adminContractAddress The EndaomentAdmin contract address. + * @param role The desired IEndaomentAdmin.Role to check against. Permitted + * roles are ADMIN (6), ACCOUNTANT (2), REVIEWER (3), FUND_FACTORY (4) and ORG_FACTORY(5). + */ + modifier onlyAddressOrAdminOrRole( + address allowedAddress, + address adminContractAddress, + IEndaomentAdmin.Role role + ) { require( allowedAddress != address(0), "Administratable: Allowed address must not be the zero address" ); - + bool isAllowed = (msg.sender == allowedAddress); if (!isAllowed) { - _onlyAdminOrRole(adminContractAddress, role); + _onlyAdminOrRole(adminContractAddress, role); } _; } - + /** * @notice Returns true if two strings are equal, false otherwise * @param s1 First string to compare diff --git a/contracts/EndaomentAdmin.sol b/contracts/EndaomentAdmin.sol index 20ab958..8625550 100644 --- a/contracts/EndaomentAdmin.sol +++ b/contracts/EndaomentAdmin.sol @@ -104,6 +104,13 @@ contract TwoStepOwnable { } } +/** + * @title EndaomentAdmin + * @author rheeger + * @notice Provides admin controls for the Endaoment contract ecosystem using + * a roles-based system. Available roles are PAUSER (1), ACCOUNTANT (2), + * REVIEWER (3), FUND_FACTORY (4), ORG_FACTORY (5), and ADMIN (6). + */ contract EndaomentAdmin is IEndaomentAdmin, TwoStepOwnable { // Maintain a role status mapping with assigned accounts and paused states. mapping(uint256 => RoleStatus) private _roles; @@ -181,7 +188,8 @@ contract EndaomentAdmin is IEndaomentAdmin, TwoStepOwnable { /** * @notice External view function to check the account currently holding the * given role. - * @return The address of the current admin, or the null + * @param role The desired role to fetch the current address of. + * @return The address of the requested role, or the null * address if none is set. */ function getRoleAddress(Role role) external override view returns (address) { @@ -231,8 +239,7 @@ contract EndaomentAdmin is IEndaomentAdmin, TwoStepOwnable { * @notice Modifier that throws if called by any account other than the owner * or the supplied role, or if the caller is not the owner and the role in * question is paused. - * @param role The role to require unless the caller is the owner. Permitted - * roles are bot commander (0) and pauser (1). + * @param role The role to require unless the caller is the owner. */ modifier onlyAdminOr(Role role) { if (!isOwner()) { diff --git a/contracts/EndaomentAdminStorage.sol b/contracts/EndaomentAdminStorage.sol index c1f7f64..d45ada1 100644 --- a/contracts/EndaomentAdminStorage.sol +++ b/contracts/EndaomentAdminStorage.sol @@ -4,12 +4,20 @@ pragma solidity ^0.6.10; import "./Administratable.sol"; +// ENDAOMENT ADMIN STORAGE CONTRACT +/** + * @title EndaomentAdminStorage + * @author rheeger + * @notice Stores the contract address of the EndaomentAdmin, + * for use in references by the Org and Fund factories and + * subsequently deployed Org and Fund contracts. + */ contract EndaomentAdminStorage is Administratable { address public endaomentAdmin; event EndaomentAdminChanged(address indexed oldAddress, address indexed newAddress); /** - * @notice Update address of the endaomentAdmin contract + * @notice Updates address of the endaomentAdmin contract and emits `EndaomentAdminChanged` event. * @param newAdmin New address of the endaomentAdmin contract */ function updateEndaomentAdmin(address newAdmin) public onlyAdmin(endaomentAdmin) { diff --git a/contracts/Fund.sol b/contracts/Fund.sol index 99205bf..5e5e3fe 100644 --- a/contracts/Fund.sol +++ b/contracts/Fund.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import "./Administratable.sol"; import "./OrgFactory.sol"; -import "./IFactory.sol"; +import "./interfaces/IFactory.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; // FUND CONTRACT @@ -24,7 +24,7 @@ contract Fund is Administratable { using SafeERC20 for IERC20; // ========== STRUCTS & EVENTS ========== - + struct Grant { string description; uint256 value; @@ -59,7 +59,7 @@ contract Fund is Administratable { // ========== Fund Management & Info ========== /** - * @notice Change Fund Primary Advisor + * @notice Changes Fund Primary Advisor and emits a `ManagerChanged` event * @param newManager The address of the new PrimaryAdvisor. */ function changeManager(address newManager) @@ -75,6 +75,7 @@ contract Fund is Administratable { * @notice Checks recipient of a Grant is an address created by the OrgFactory * @param recipient The address of the Grant recipient. * @param orgFactoryContractAddress Address of the OrgFactory contract. + * @return Boolean of status of given recipient status. */ function checkRecipient(address recipient, address orgFactoryContractAddress) public @@ -90,16 +91,10 @@ contract Fund is Administratable { /** * @notice Returns summary of details about the fund [tokenBalance, number of grants, managerAddress]. - * @param tokenAddress The token address of the stablecoin being used by the web-server. + * @param tokenAddress The token address of the ERC20 being used by the web-server. + * @return Returns the token balance of the given tokenAddress and the address of the Fund's manager. */ - function getSummary(address tokenAddress) - external - view - returns ( - uint256, - address - ) - { + function getSummary(address tokenAddress) external view returns (uint256, address) { require(tokenAddress != address(0), "Fund: Token address cannot be the zero address"); IERC20 tokenContract = IERC20(tokenAddress); uint256 balance = tokenContract.balanceOf(address(this)); @@ -108,7 +103,7 @@ contract Fund is Administratable { } /** - * @notice Create new Grant Recommendation + * @notice Creates new Grant Recommendation and emits a `GrantCreated` event. * @param grantId UUID representing this grant * @param description The address of the Owner. * @param value The value of the grant in base units. @@ -119,18 +114,23 @@ contract Fund is Administratable { string calldata description, uint256 value, address recipient - ) public onlyAddressOrAdminOrRole(manager, fundFactoryContract.endaomentAdmin(), IEndaomentAdmin.Role.REVIEWER) { + ) + public + onlyAddressOrAdminOrRole( + manager, + fundFactoryContract.endaomentAdmin(), + IEndaomentAdmin.Role.REVIEWER + ) + { require(!isEqual(grantId, ""), "Fund: Must provide a grantId"); require(!isEqual(description, ""), "Fund: Must provide a description"); EndaomentAdmin endaomentAdmin = EndaomentAdmin(fundFactoryContract.endaomentAdmin()); require( - checkRecipient(recipient, endaomentAdmin.getRoleAddress(IEndaomentAdmin.Role.ORG_FACTORY)) == true, + checkRecipient(recipient, endaomentAdmin.getRoleAddress(IEndaomentAdmin.Role.ORG_FACTORY)) == + true, "Fund: Recipient contract was not created by the OrgFactory and is not allowed." ); - require( - pendingGrants[grantId].recipient == address(0), - "Fund: Grant was already created." - ); + require(pendingGrants[grantId].recipient == address(0), "Fund: Grant was already created."); Grant memory newGrant = Grant({ description: description, @@ -140,10 +140,10 @@ contract Fund is Administratable { }); emit GrantCreated(grantId, newGrant); pendingGrants[grantId] = newGrant; - } + } /** - * @notice Update Grant Recommendation + * @notice Updates Grant Recommendation and emits a `GrantUpdated` event. * @param grantId UUID representing this grant * @param description The address of the Owner. * @param value The value of the grant in base units. @@ -154,21 +154,24 @@ contract Fund is Administratable { string calldata description, uint256 value, address recipient - ) public onlyAddressOrAdminOrRole(manager, fundFactoryContract.endaomentAdmin(), IEndaomentAdmin.Role.REVIEWER) { + ) + public + onlyAddressOrAdminOrRole( + manager, + fundFactoryContract.endaomentAdmin(), + IEndaomentAdmin.Role.REVIEWER + ) + { require(!isEqual(grantId, ""), "Fund: Must provide a grantId"); require(!isEqual(description, ""), "Fund: Must provide a description"); EndaomentAdmin endaomentAdmin = EndaomentAdmin(fundFactoryContract.endaomentAdmin()); require( - checkRecipient(recipient, endaomentAdmin.getRoleAddress(IEndaomentAdmin.Role.ORG_FACTORY)) == true, + checkRecipient(recipient, endaomentAdmin.getRoleAddress(IEndaomentAdmin.Role.ORG_FACTORY)) == + true, "Fund: Recipient contract was not created by the OrgFactory and is not allowed." ); - require( - pendingGrants[grantId].recipient != address(0), - "Fund: Grant does not exist." - ); - require(pendingGrants[grantId].complete == false, - "Fund: Grant is already finalized." - ); + require(pendingGrants[grantId].recipient != address(0), "Fund: Grant does not exist."); + require(pendingGrants[grantId].complete == false, "Fund: Grant is already finalized."); Grant memory replacementGrant = Grant({ description: description, value: value, @@ -180,34 +183,34 @@ contract Fund is Administratable { } /** - * @notice Reject Grant Recommendation + * @notice Rejects Grant Recommendation and emits a `GrantRejected` event. * @param grantId UUID representing this grant */ - function rejectGrant( - string calldata grantId - ) public onlyAddressOrAdminOrRole(manager, fundFactoryContract.endaomentAdmin(), IEndaomentAdmin.Role.REVIEWER) { + function rejectGrant(string calldata grantId) + public + onlyAddressOrAdminOrRole( + manager, + fundFactoryContract.endaomentAdmin(), + IEndaomentAdmin.Role.REVIEWER + ) + { require(!isEqual(grantId, ""), "Fund: Must provide a grantId"); - require( - pendingGrants[grantId].recipient != address(0), - "Fund: Grant does not exist." - ); - require(pendingGrants[grantId].complete == false, - "Fund: Grant is already finalized." - ); - + require(pendingGrants[grantId].recipient != address(0), "Fund: Grant does not exist."); + require(pendingGrants[grantId].complete == false, "Fund: Grant is already finalized."); + delete pendingGrants[grantId]; emit GrantRejected(grantId); } /** - * @notice Approve Grant Recommendation + * @notice Approves Grant Recommendation and emits a `GrantFinalized` event. * @param grantId UUID of the grant being finalized - * @param tokenAddress The stablecoin's token address. + * @param tokenAddress The ERC20 token address of the token prescribed by the web-server. */ - function finalizeGrant( - string calldata grantId, - address tokenAddress - ) public onlyAdminOrRole(fundFactoryContract.endaomentAdmin(), IEndaomentAdmin.Role.ACCOUNTANT) { + function finalizeGrant(string calldata grantId, address tokenAddress) + public + onlyAdminOrRole(fundFactoryContract.endaomentAdmin(), IEndaomentAdmin.Role.ACCOUNTANT) + { require(!isEqual(grantId, ""), "Fund: Must provide a grantId"); require(tokenAddress != address(0), "Fund: Token address cannot be the zero address"); Grant storage grant = pendingGrants[grantId]; @@ -216,14 +219,14 @@ contract Fund is Administratable { require(grant.complete == false, "Fund: Grant is already finalized."); // Effects IERC20 tokenContract = IERC20(tokenAddress); - // Process fees: uint256 fee = grant.value.div(100); uint256 finalGrant = grant.value.sub(fee); grant.complete = true; emit GrantFinalized(grantId, grant); // Interactions - address endaomentAdminAdminAddress = EndaomentAdmin(fundFactoryContract.endaomentAdmin()).getRoleAddress(IEndaomentAdmin.Role.ADMIN); + address endaomentAdminAdminAddress = EndaomentAdmin(fundFactoryContract.endaomentAdmin()) + .getRoleAddress(IEndaomentAdmin.Role.ADMIN); tokenContract.safeTransfer(endaomentAdminAdminAddress, fee); tokenContract.safeTransfer(grant.recipient, finalGrant); } diff --git a/contracts/FundFactory.sol b/contracts/FundFactory.sol index 4d044e1..e49c31e 100644 --- a/contracts/FundFactory.sol +++ b/contracts/FundFactory.sol @@ -9,10 +9,8 @@ import "./Fund.sol"; /** * @title FundFactory * @author rheeger - * @notice FundFactory is a contract that allows the EndaomentAdmin to - * instantiate new Fund contracts. It also provides for fetching of - * individual Org contract addresses as well as a list of all - * allowedOrgs. + * @notice FundFactory is a contract that allows the Endaoment ADMIN or ACCOUNTANT to + * instantiate new Fund contracts. */ contract FundFactory is EndaomentAdminStorage { // ========== EVENTS ========== @@ -31,7 +29,7 @@ contract FundFactory is EndaomentAdminStorage { // ========== Fund Creation & Management ========== /** - * @notice Creates new Fund and emits FundCreated event. + * @notice Creates new Fund and emits a `FundCreated` event. * @param managerAddress The address of the Fund's Primary Advisor */ function createFund(address managerAddress) diff --git a/contracts/Org.sol b/contracts/Org.sol index f4a5f3c..5a8655d 100644 --- a/contracts/Org.sol +++ b/contracts/Org.sol @@ -4,7 +4,7 @@ pragma solidity ^0.6.10; pragma experimental ABIEncoderV2; import "./Administratable.sol"; -import "./IFactory.sol"; +import "./interfaces/IFactory.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; @@ -34,7 +34,7 @@ contract Org is Administratable { event ClaimRejected(string claimId, Claim claim); // ========== STATE VARIABLES ========== - + IFactory public orgFactoryContract; uint256 public taxId; mapping(string => Claim) public pendingClaims; // claim UUID to Claim @@ -57,7 +57,7 @@ contract Org is Administratable { // ========== Org Management & Info ========== /** - * @notice Create Organization Claim + * @notice Creates Organization Claim and emits a `ClaimCreated` event * @param claimId UUID representing this claim * @param fName First name of Administrator * @param lName Last name of Administrator @@ -93,7 +93,7 @@ contract Org is Administratable { } /** - * @notice Approving Organization Claim + * @notice Approves an Organization Claim and emits a `ClaimApproved` event * @param claimId UUID of the claim being approved */ function approveClaim(string calldata claimId) @@ -102,16 +102,14 @@ contract Org is Administratable { { require(!isEqual(claimId, ""), "Fund: Must provide a claimId"); Claim storage claim = pendingClaims[claimId]; - require(claim.desiredWallet != address(0), - "Org: claim does not exist" - ); + require(claim.desiredWallet != address(0), "Org: claim does not exist"); emit ClaimApproved(claimId, claim); activeClaim = claim; delete pendingClaims[claimId]; } /** - * @notice Rejecting Organization Claim + * @notice Rejects an Organization Claim and emits a 'ClaimRejected` event * @param claimId UUID of the claim being rejected */ function rejectClaim(string calldata claimId) @@ -120,9 +118,7 @@ contract Org is Administratable { { require(!isEqual(claimId, ""), "Fund: Must provide a claimId"); Claim storage claim = pendingClaims[claimId]; - require(claim.desiredWallet != address(0), - "Org: claim does not exist" - ); + require(claim.desiredWallet != address(0), "Org: claim does not exist"); emit ClaimRejected(claimId, claim); @@ -130,8 +126,8 @@ contract Org is Administratable { } /** - * @notice Cashing out Organization Contract - * @param tokenAddress Stablecoin address of desired token withdrawal + * @notice Cashes out Organization Contract and emits a `CashOutComplete` event + * @param tokenAddress ERC20 address of desired token withdrawal */ function cashOutOrg(address tokenAddress) public diff --git a/contracts/OrgFactory.sol b/contracts/OrgFactory.sol index 9c658c1..0d12dba 100644 --- a/contracts/OrgFactory.sol +++ b/contracts/OrgFactory.sol @@ -21,12 +21,12 @@ contract OrgFactory is EndaomentAdminStorage { event OrgStatusChanged(address indexed orgAddress, bool indexed isAllowed); // ========== STATE VARIABLES========== - + mapping(address => bool) public allowedOrgs; // ========== CONSTRUCTOR ========== /** - * @notice Create new Org Factory + * @notice Creates new Org Factory and emits a `EndaomentAdminChanged` event * @param adminContractAddress Address of EndaomentAdmin contract. */ constructor(address adminContractAddress) public { @@ -37,7 +37,7 @@ contract OrgFactory is EndaomentAdminStorage { // ========== Org Creation & Management ========== /** - * @notice Create new Org Contract + * @notice Creates new Org Contract and emits a `OrgCreated` event * @param ein The U.S. Tax Identification Number for the Organization */ function createOrg(uint256 ein) @@ -50,18 +50,15 @@ contract OrgFactory is EndaomentAdminStorage { } /** - * @notice Toggle whether Org is allowed + * @notice Toggles whether Org is allowed and emits a `OrgStatusChanged` event * @param orgAddress THe address of the Org contract. */ function toggleOrg(address orgAddress) public onlyAdminOrRole(endaomentAdmin, IEndaomentAdmin.Role.REVIEWER) - { - require( - Org(orgAddress).taxId() != 0, - "OrgFactory: Not a valid org." - ); - allowedOrgs[orgAddress] = !allowedOrgs[orgAddress]; - emit OrgStatusChanged(orgAddress, allowedOrgs[orgAddress]); - } + { + require(Org(orgAddress).taxId() != 0, "OrgFactory: Not a valid org."); + allowedOrgs[orgAddress] = !allowedOrgs[orgAddress]; + emit OrgStatusChanged(orgAddress, allowedOrgs[orgAddress]); + } } diff --git a/contracts/IFactory.sol b/contracts/interfaces/IFactory.sol similarity index 100% rename from contracts/IFactory.sol rename to contracts/interfaces/IFactory.sol diff --git a/docs/Administratable.md b/docs/Administratable.md index d0868ea..d74a139 100644 --- a/docs/Administratable.md +++ b/docs/Administratable.md @@ -1,9 +1,11 @@ ## Contract: `Administratable.sol` - Provides two modifiers allowing contracts administered by the EndaomentAdmin contract to properly restrict method calls -based on the a given role. +based on the a given role. Also provides a utility function for +validating string input arguments. + +## Modifiers ### `onlyAdmin(address adminContractAddress)` onlyAdmin checks that the caller is the EndaomentAdmin @@ -25,7 +27,35 @@ _Parameters:_ - `role`: The role to require unless the caller is the owner. Permitted -roles are admin (0), accountant (2), and reviewer (3). +roles are ADMIN (6), ACCOUNTANT (2), REVIEWER (3), FUND_FACTORY (4) and ORG_FACTORY(5). + +### `onlyAddressOrAdminOrRole(address allowedAddress, address adminContractAddress, enum IEndaomentAdmin.Role role)` +Checks that the caller is either a provided adress, admin or role. + + + +_Parameters:_ + +- `allowedAddress`: An exempt address provided that shall be allowed to proceed. + + +- `adminContractAddress`: The EndaomentAdmin contract address. + + + +- `role`: The desired IEndaomentAdmin.Role to check against. Permitted +roles are ADMIN (6), ACCOUNTANT (2), REVIEWER (3), FUND_FACTORY (4) and ORG_FACTORY(5). + + +## Methods +### `isEqual(string s1, string s2) → bool` - internal +Returns true if two strings are equal, false otherwise + + + +_Parameters:_ + - `s1`: First string to compare + - `s2`: Second string to compare diff --git a/docs/EndaomentAdmin.md b/docs/EndaomentAdmin.md index ce7b69a..b308e31 100644 --- a/docs/EndaomentAdmin.md +++ b/docs/EndaomentAdmin.md @@ -1,7 +1,10 @@ ## Contract: `EndaomentAdmin.sol` +Provides admin controls for the Endaoment contract ecosystem using +a roles-based system. Available roles are PAUSER (1), ACCOUNTANT (2), +REVIEWER (3), FUND_FACTORY (4), ORG_FACTORY (5), and ADMIN (6). - +## Modifiers ### `onlyAdminOr(enum IEndaomentAdmin.Role role)` Modifier that throws if called by any account other than the owner or the supplied role, or if the caller is not the owner and the role in @@ -11,22 +14,21 @@ question is paused. _Parameters:_ -- `role`: The role to require unless the caller is the owner. Permitted -roles are bot commander (0) and pauser (1). +- `role`: The role to require unless the caller is the owner. -### `setRole(enum IEndaomentAdmin.Role role, address account)` (public) +## Methods +### `setRole(enum IEndaomentAdmin.Role role, address account)` - public Set a new account on a given role and emit a `RoleModified` event if the role holder has changed. Only the owner may call this function. _Parameters:_ -- `role`: The role that the account will be set for. - -- `account`: The account to set as the designated role bearer. + - `role`: The role that the account will be set for. + - `account`: The account to set as the designated role bearer. -### `removeRole(enum IEndaomentAdmin.Role role)` (public) +### `removeRole(enum IEndaomentAdmin.Role role)` - public Remove any current role bearer for a given role and emit a `RoleModified` event if a role holder was previously set. Only the owner may call this function. @@ -34,9 +36,9 @@ may call this function. _Parameters:_ -- `role`: The role that the account will be removed from. + - `role`: The role that the account will be removed from. -### `pause(enum IEndaomentAdmin.Role role)` (public) +### `pause(enum IEndaomentAdmin.Role role)` - public Pause a currently unpaused role and emit a `RolePaused` event. Only the owner or the designated pauser may call this function. Also, bear in mind that only the owner may unpause a role once paused. @@ -44,18 +46,18 @@ mind that only the owner may unpause a role once paused. _Parameters:_ -- `role`: The role to pause. + - `role`: The role to pause. -### `unpause(enum IEndaomentAdmin.Role role)` (public) +### `unpause(enum IEndaomentAdmin.Role role)` - public Unpause a currently paused role and emit a `RoleUnpaused` event. Only the owner may call this function. _Parameters:_ -- `role`: The role to pause. + - `role`: The role to pause. -### `isPaused(enum IEndaomentAdmin.Role role) → bool` (external) +### `isPaused(enum IEndaomentAdmin.Role role) → bool` - external External view function to check whether or not the functionality associated with a given role is currently paused or not. The owner or the pauser may pause any given role (including the pauser itself), but only the @@ -65,25 +67,27 @@ functions directly. _Parameters:_ -- `role`: The role to check the pause status on. + - `role`: The role to check the pause status on. -### `isRole(enum IEndaomentAdmin.Role role) → bool` (external) +### `isRole(enum IEndaomentAdmin.Role role) → bool` - external External view function to check whether the caller is the current role holder. _Parameters:_ -- `role`: The role to check for. + - `role`: The role to check for. -### `getRoleAddress(enum IEndaomentAdmin.Role role) → address` (external) +### `getRoleAddress(enum IEndaomentAdmin.Role role) → address` - external External view function to check the account currently holding the given role. +_Parameters:_ + - `role`: The desired role to fetch the current address of. diff --git a/docs/EndaomentAdminStorage.md b/docs/EndaomentAdminStorage.md new file mode 100644 index 0000000..92689e0 --- /dev/null +++ b/docs/EndaomentAdminStorage.md @@ -0,0 +1,19 @@ +## Contract: `EndaomentAdminStorage.sol` +Stores the contract address of the EndaomentAdmin, +for use in references by the Org and Fund factories and +subsequently deployed Org and Fund contracts. + + + +## Methods +### `updateEndaomentAdmin(address newAdmin)` - public +Updates address of the endaomentAdmin contract and emits `EndaomentAdminChanged` event. + + + +_Parameters:_ + - `newAdmin`: New address of the endaomentAdmin contract + + +## Events +- `EndaomentAdminChanged(address oldAddress, address newAddress)` diff --git a/docs/Fund.md b/docs/Fund.md index f38e62d..8f6723e 100644 --- a/docs/Fund.md +++ b/docs/Fund.md @@ -7,89 +7,87 @@ a SafeMath transfer of a 1% fee to the EndaomentAdmin and the remainder to the recipient Org contract. -### `restricted()` -Restricts method access to fund's manager - - - -### `constructor(address fundManager, address adminContractAddress)` (public) +## Methods +### `constructor(address fundManager, address fundFactory)` - public Create new Fund _Parameters:_ -- `fundManager`: Address of the Fund's Primary Advisor - -- `adminContractAddress`: Address of the EndaomentAdmin contract. + - `fundManager`: Address of the Fund's Primary Advisor + - `fundFactory`: Address of the Factory contract. -### `changeManager(address newManager, address adminContractAddress)` (public) -Change Fund Primary Advisor +### `changeManager(address newManager)` - public +Changes Fund Primary Advisor and emits a `ManagerChanged` event _Parameters:_ -- `newManager`: The address of the new PrimaryAdvisor. + - `newManager`: The address of the new PrimaryAdvisor. -- `adminContractAddress`: Address of the EndaomentAdmin contract. - -### `checkRecipient(address recipient, address orgFactoryContractAddress) → bool` (public) +### `checkRecipient(address recipient, address orgFactoryContractAddress) → bool` - public Checks recipient of a Grant is an address created by the OrgFactory _Parameters:_ -- `recipient`: The address of the Grant recipient. + - `recipient`: The address of the Grant recipient. + - `orgFactoryContractAddress`: Address of the OrgFactory contract. -- `orgFactoryContractAddress`: Address of the OrgFactory contract. -### `getSummary(address tokenAddress) → uint256, uint256, address` (external) +### `getSummary(address tokenAddress) → uint256, address` - external Returns summary of details about the fund [tokenBalance, number of grants, managerAddress]. _Parameters:_ -- `tokenAddress`: The token address of the stablecoin being used by the web-server. - -### `createGrant(string description, uint256 value, address recipient, address orgFactoryContractAddress)` (public) -Create new Grant Recommendation + - `tokenAddress`: The token address of the ERC20 being used by the web-server. - -_Parameters:_ -- `description`: The address of the Owner. - -- `value`: The value of the grant in base units. - -- `recipient`: The address of the recieving organization's contract. - -- `orgFactoryContractAddress`: Address of the orgFactory Contract. - -### `finalizeGrant(uint256 index, address tokenAddress, address adminContractAddress)` (public) -Approve Grant Recommendation +### `createGrant(string grantId, string description, uint256 value, address recipient)` - public +Creates new Grant Recommendation and emits a `GrantCreated` event. _Parameters:_ -- `index`: This Grant's index position + - `grantId`: UUID representing this grant + - `description`: The address of the Owner. + - `value`: The value of the grant in base units. + - `recipient`: The address of the recieving organization's contract. -- `tokenAddress`: The stablecoin's token address. +### `updateGrant(string grantId, string description, uint256 value, address recipient)` - public +Updates Grant Recommendation and emits a `GrantUpdated` event. -- `adminContractAddress`: Address of the EndaomentAdmin contract. -### `getGrantsCount() → uint256` (external) -Returns total number of grants submitted to the fund. +_Parameters:_ + - `grantId`: UUID representing this grant + - `description`: The address of the Owner. + - `value`: The value of the grant in base units. + - `recipient`: The address of the recieving organization's contract. +### `rejectGrant(string grantId)` - public +Rejects Grant Recommendation and emits a `GrantRejected` event. -### `ManagerChanged(address newManager)` +_Parameters:_ + - `grantId`: UUID representing this grant +### `finalizeGrant(string grantId, address tokenAddress)` - public +Approves Grant Recommendation and emits a `GrantFinalized` event. -### `GrantCreated(struct Fund.Grant grant)` -### `GrantFinalized(struct Fund.Grant grant)` +_Parameters:_ + - `grantId`: UUID of the grant being finalized + - `tokenAddress`: The ERC20 token address of the token prescribed by the web-server. +## Events +- `ManagerChanged(address newManager)` +- `GrantCreated(string grantId, struct Fund.Grant grant)` +- `GrantUpdated(string grantId, struct Fund.Grant grant)` +- `GrantRejected(string grantId)` +- `GrantFinalized(string grantId, struct Fund.Grant grant)` diff --git a/docs/FundFactory.md b/docs/FundFactory.md index 6d31aa4..7a1d86a 100644 --- a/docs/FundFactory.md +++ b/docs/FundFactory.md @@ -1,44 +1,26 @@ ## Contract: `FundFactory.sol` -FundFactory is a contract that allows the EndaomentAdmin to -instantiate new Fund contracts. It also provides for fetching of -individual Org contract addresses as well as a list of all -allowedOrgs. +FundFactory is a contract that allows the Endaoment ADMIN or ACCOUNTANT to +instantiate new Fund contracts. -### `constructor(address adminContractAddress)` (public) +## Methods +### `constructor(address adminContractAddress)` - public Create new Fund Factory _Parameters:_ -- `adminContractAddress`: Address of EndaomentAdmin contract. + - `adminContractAddress`: Address of EndaomentAdmin contract. -### `createFund(address managerAddress, address adminContractAddress)` (public) -Creates new Fund and emits FundCreated event. +### `createFund(address managerAddress)` - public +Creates new Fund and emits a `FundCreated` event. _Parameters:_ -- `managerAddress`: The address of the Fund's Primary Advisor - -- `adminContractAddress`: Address of EndaomentAdmin contract. - -### `countFunds() → uint256` (external) -Returns total number of funds created by the factory. - - - - -### `getFund(uint256 index) → address` (external) -Returns address of a specific fund in createdFunds[] - - - -_Parameters:_ -- `index`: The index position of the Fund - - -### `FundCreated(address newAddress)` + - `managerAddress`: The address of the Fund's Primary Advisor +## Events +- `FundCreated(address newAddress)` diff --git a/docs/Org.md b/docs/Org.md index 5f19faf..a23ea5e 100644 --- a/docs/Org.md +++ b/docs/Org.md @@ -6,77 +6,72 @@ the organization can directly receive grant awards from Endaoment Funds. -### `constructor(uint256 ein, address adminContractAddress)` (public) +## Methods +### `constructor(uint256 ein, address orgFactory)` - public Create new Organization Contract _Parameters:_ -- `ein`: The U.S. Tax Identification Number for the Organization + - `ein`: The U.S. Tax Identification Number for the Organization + - `orgFactory`: Address of the Factory contract. -- `adminContractAddress`: Contract Address for Endaoment Admin - -### `claimRequest(string fName, string lName, bool fSub, string eMail, address orgAdminAddress)` (public) -Create Organization Claim +### `claimRequest(string claimId, string fName, string lName, string eMail, address orgAdminWalletAddress)` - public +Creates Organization Claim and emits a `ClaimCreated` event _Parameters:_ -- `fName`: First name of Administrator + - `claimId`: UUID representing this claim + - `fName`: First name of Administrator + - `lName`: Last name of Administrator + - `eMail`: Email contact for Organization Administrator. + - `orgAdminWalletAddress`: Wallet address of Organization's Administrator. -- `lName`: Last name of Administrator +### `approveClaim(string claimId)` - public +Approves an Organization Claim and emits a `ClaimApproved` event -- `fSub`: Information Submitted successfully. -- `eMail`: Email contact for Organization Administrator. -- `orgAdminAddress`: Wallet address of Organization's Administrator. +_Parameters:_ + - `claimId`: UUID of the claim being approved -### `approveClaim(uint256 index, address adminContractAddress)` (public) -Approving Organization Claim +### `rejectClaim(string claimId)` - public +Rejects an Organization Claim and emits a 'ClaimRejected` event _Parameters:_ -- `index`: Index value of Claim. - -- `adminContractAddress`: Contract Address for Endaoment Admin + - `claimId`: UUID of the claim being rejected -### `cashOutOrg(address desiredWithdrawalAddress, address tokenAddress, address adminContractAddress)` (public) -Cashing out Organization Contract +### `cashOutOrg(address tokenAddress)` - public +Cashes out Organization Contract and emits a `CashOutComplete` event _Parameters:_ -- `desiredWithdrawalAddress`: Destination for withdrawal - -- `tokenAddress`: Stablecoin address of desired token withdrawal - -- `adminContractAddress`: Contract Address for Endaoment Admin + - `tokenAddress`: ERC20 address of desired token withdrawal -### `getTokenBalance(address tokenAddress) → uint256` (external) +### `getTokenBalance(address tokenAddress) → uint256` - external Retrieves Token Balance of Org Contract _Parameters:_ -- `tokenAddress`: Address of desired token to query for balance - - -### `getClaimsCount() → uint256` (external) -Retrieves Count of Claims Made - - - + - `tokenAddress`: Address of desired token to query for balance +### `orgWallet() → address` - public +Org Wallet convenience accessor -### `CashOutComplete(uint256 cashOutAmount)` -### `ClaimCreated(struct Org.Claim claim)` -### `ClaimApproved(struct Org.Claim claim)` +## Events +- `CashOutComplete(uint256 cashOutAmount)` +- `ClaimCreated(string claimId, struct Org.Claim claim)` +- `ClaimApproved(string claimId, struct Org.Claim claim)` +- `ClaimRejected(string claimId, struct Org.Claim claim)` diff --git a/docs/OrgFactory.md b/docs/OrgFactory.md index 4fdfe7d..cb614d2 100644 --- a/docs/OrgFactory.md +++ b/docs/OrgFactory.md @@ -6,47 +6,32 @@ allowedOrgs. -### `constructor(address adminContractAddress)` (public) -Create new Org Factory +## Methods +### `constructor(address adminContractAddress)` - public +Creates new Org Factory and emits a `EndaomentAdminChanged` event _Parameters:_ -- `adminContractAddress`: Address of EndaomentAdmin contract. + - `adminContractAddress`: Address of EndaomentAdmin contract. -### `createOrg(uint256 ein, address adminContractAddress)` (public) - Create new Org Contract +### `createOrg(uint256 ein)` - public +Creates new Org Contract and emits a `OrgCreated` event _Parameters:_ -- `ein`: The U.S. Tax Identification Number for the Organization + - `ein`: The U.S. Tax Identification Number for the Organization -- `adminContractAddress`: Contract address for Endaoment Admin - -### `countDeployedOrgs() → uint256` (external) -Returns total number Org contracts created by the factory. - - - - -### `getDeployedOrg(uint256 index) → address` (external) -Returns address of given index postiion in deployedOrgs[]. - - - -_Parameters:_ -- `index`: Array position of requested org - -### `getAllowedOrg(address org) → bool` (external) -Returns boolean if provided address is present in allowedOrgs[]. +### `toggleOrg(address orgAddress)` - public +Toggles whether Org is allowed and emits a `OrgStatusChanged` event _Parameters:_ -- `org`: address of the organization contract requested. - - -### `OrgCreated(address newAddress)` + - `orgAddress`: THe address of the Org contract. +## Events +- `OrgCreated(address newAddress)` +- `OrgStatusChanged(address orgAddress, bool isAllowed)` diff --git a/docs/contract.hbs b/docs/contract.hbs index 03292ee..3b231cd 100644 --- a/docs/contract.hbs +++ b/docs/contract.hbs @@ -2,6 +2,9 @@ {{{natspec.userdoc}}} {{{natspec.devdoc}}} +{{#if ownModifiers}} +## Modifiers +{{/if}} {{#each ownModifiers}} ### `{{name}}({{args}})` {{#if natspec.userdoc}} @@ -17,31 +20,28 @@ {{/each}} {{/each}} +{{#if ownFunctions}} +## Methods +{{/if}} {{#each ownFunctions}} -### `{{name}}({{args}}){{#if outputs}} → {{outputs}}{{/if}}` ({{visibility}}) +### `{{name}}({{args}}){{#if outputs}} → {{outputs}}{{/if}}` - {{visibility}} {{#if natspec.userdoc}} {{{natspec.userdoc}}} {{/if}} {{#if natspec.params}}_Parameters:_{{/if}} -{{#each natspec.params}} -- `{{param}}`: {{description}} -{{/each}} +{{#each natspec.params}} - `{{param}}`: {{description}}{{/each}} {{/each}} +{{#if ownEvents}} +## Events +{{/if}} {{#each ownEvents}} -### `{{name}}({{args}})` +- `{{name}}({{args}})` {{#if natspec.userdoc}} {{{natspec.userdoc}}} {{/if}} - -{{#if natspec.params}}_Parameters:_{{/if}} -{{#each natspec.params}} - -- `{{param}}`: {{description}} - -{{/each}} {{/each}} \ No newline at end of file diff --git a/docs/interfaces/IEndaomentAdmin.md b/docs/interfaces/IEndaomentAdmin.md index 2e85901..3b4e18e 100644 --- a/docs/interfaces/IEndaomentAdmin.md +++ b/docs/interfaces/IEndaomentAdmin.md @@ -3,41 +3,44 @@ Interface of the EndaomentAdmin contract -### `setRole(enum IEndaomentAdmin.Role role, address account)` (external) +## Methods +### `setRole(enum IEndaomentAdmin.Role role, address account)` - external -### `removeRole(enum IEndaomentAdmin.Role role)` (external) +### `removeRole(enum IEndaomentAdmin.Role role)` - external -### `pause(enum IEndaomentAdmin.Role role)` (external) +### `pause(enum IEndaomentAdmin.Role role)` - external -### `unpause(enum IEndaomentAdmin.Role role)` (external) -### `isPaused(enum IEndaomentAdmin.Role role) → bool` (external) +### `unpause(enum IEndaomentAdmin.Role role)` - external -### `isRole(enum IEndaomentAdmin.Role role) → bool` (external) +### `isPaused(enum IEndaomentAdmin.Role role) → bool` - external -### `getRoleAddress(enum IEndaomentAdmin.Role role) → address` (external) +### `isRole(enum IEndaomentAdmin.Role role) → bool` - external -### `RoleModified(enum IEndaomentAdmin.Role role, address account)` -### `RolePaused(enum IEndaomentAdmin.Role role)` +### `getRoleAddress(enum IEndaomentAdmin.Role role) → address` - external -### `RoleUnpaused(enum IEndaomentAdmin.Role role)` + +## Events +- `RoleModified(enum IEndaomentAdmin.Role role, address account)` +- `RolePaused(enum IEndaomentAdmin.Role role)` +- `RoleUnpaused(enum IEndaomentAdmin.Role role)` diff --git a/docs/interfaces/IFactory.md b/docs/interfaces/IFactory.md new file mode 100644 index 0000000..ae5bc96 --- /dev/null +++ b/docs/interfaces/IFactory.md @@ -0,0 +1,12 @@ +## Contract: `IFactory.sol` + + + + +## Methods +### `endaomentAdmin() → address` - external + + + + + diff --git a/docs/mocks/ERC20Mock.md b/docs/mocks/ERC20Mock.md index 2c12402..9e0eed2 100644 --- a/docs/mocks/ERC20Mock.md +++ b/docs/mocks/ERC20Mock.md @@ -3,23 +3,29 @@ -### `constructor(string name, string symbol, address initialAccount, uint256 initialBalance)` (public) +## Methods +### `constructor(string name, string symbol, address initialAccount, uint256 initialBalance)` - public -### `mint(address account, uint256 amount)` (public) +### `mint(address account, uint256 amount)` - public -### `burn(address account, uint256 amount)` (public) +### `burn(address account, uint256 amount)` - public -### `transferInternal(address from, address to, uint256 value)` (public) -### `approveInternal(address owner, address spender, uint256 value)` (public) +### `transferInternal(address from, address to, uint256 value)` - public + + + + +### `approveInternal(address owner, address spender, uint256 value)` - public +