Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

Feat/optimize ci workflow #144

Closed
Closed
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
62 changes: 20 additions & 42 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
name: UnitTest
name: Foundry CI

on: [pull_request]

env:
FOUNDRY_PROFILE: ci
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
on:
pull_request:
branches:
- main

jobs:

# Add job timestamp
print_timestamp:
runs-on: ubuntu-latest
steps:
- name: Generate timestamp
run: |
echo "TIMESTAMP=$(TZ='America/Los_Angeles' date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV

- name: Print timestamp
run: |
echo "Execution time (Pacific Time Zone) $TIMESTAMP"

foundry-test:
strategy:
fail-fast: true

name: Foundry Unit Test
runs-on: ubuntu-latest
needs: print_timestamp
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: recursive
fetch-depth: 0

- name: List files in the repository
run: |
ls -R ${{ github.workspace }}

- name: Test Env Variables
env:
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
run: |
echo "MAINNET_RPC_URL is ${{ secrets.MAINNET_RPC_URL }}"
echo "env.MAINNET_RPC_URL is $MAINNET_RPC_URL"
echo "env.FOUNDRY_PROFILE is $FOUNDRY_PROFILE"
echo "DONE."

- name: Run install
uses: borales/actions-yarn@v4
with:
Expand All @@ -43,36 +41,16 @@ jobs:
with:
version: nightly

- name: List files in the repository
run: |
ls -R ${{ github.workspace }}

# first, build contracts excluding the tests and scripts. Check contract sizes in this step.
# then, build contracts including the tests and scripts. Don't check contract sizes.
- name: Run Forge build
run: |
forge --version
forge build --force --sizes --skip test --skip script
forge build
id: build

- name: Run Forge tests
run: |
forge test -vvv --fork-url https://gateway.tenderly.co/public/sepolia --fork-block-number 5196000
id: forge-test
forge test -v --fork-url https://gateway.tenderly.co/public/sepolia --fork-block-number 5196000

- name: Run solhint
run: npx solhint contracts/**/*.sol

- name: Run solhint
run: npx solhint contracts/*.sol

# - name: Gas Difference
# run:
# forge snapshot --gas-report --diff --desc
# id: forge-gas-snapshot-diff

# - name: Code Coverage
# run:
# forge coverage --report lcov --report summary
# id: forge-code-coverage
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ docs/
.env

.idea/
.github/
node_modules/

.vscode
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/openzeppelin-foundry-upgrades"]
path = lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
7 changes: 3 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ clean :; npx hardhat clean
# Remove modules
forge-remove :; rm -rf .gitmodules && rm -rf .git/modules/* && rm -rf lib && touch .gitmodules && git add . && git commit -m "modules"

install :; yarn install
install :
yarn install

# Update Dependencies
forge-update :; forge update

forge-build :; forge build
build :; npx hardhat compile

test :; forge test
test :; forge test --ffi

snapshot :; forge snapshot

Expand Down Expand Up @@ -59,7 +60,6 @@ abi:
@$(call generate_abi,"RoyaltyModule","./modules/royalty-module")
@$(call generate_abi,"LSClaimer","./modules/royalty-module/policies")
@$(call generate_abi,"RoyaltyPolicyLS","./modules/royalty-module/policies")
@$(call generate_abi,"RegistrationModule","./modules")
@$(call generate_abi,"IPAssetRenderer","./registries/metadata")
@$(call generate_abi,"IPMetadataProvider","./registries/metadata")
@$(call generate_abi,"MetadataProviderV1","./registries/metadata")
Expand All @@ -78,4 +78,3 @@ deploy-goerli :; npx hardhat run ./script/deploy-reveal-engine.js --network goer
verify-goerli :; npx hardhat verify --network goerli ${contract}

anvil :; anvil -m 'test test test test test test test test test test test junk'

12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ yarn # this installs packages
make # this builds
```

## Verify Upgrade Storage Layout (before scripts or tests)

```sh
forge clean
forge compile
npx @openzeppelin/upgrades-core@^1.32.3 validate out/build-info
```

## Testing

```
Expand Down Expand Up @@ -140,7 +148,7 @@ And get your slither output.

# Licensing

The license for Story Protocol Core is the Business Source License 1.1 (BUSL-1.1), see LICENSE.
The license for Story Protocol Core is the Business Source License 1.1 (BUSL-1.1), see LICENSE.

After you have integrated our SDK and/or API with your application, in the Terms of Service for your application with your end users (which govern your end users’ use of and access to your application), you must include the following sentence:

Expand All @@ -163,4 +171,4 @@ docgen: {
}
```

You can refer to the [config.ts](https://github.com/OpenZeppelin/solidity-docgen/blob/master/src/config.ts) of solidity-docgen for the full list of configurable parameters.
You can refer to the [config.ts](https://github.com/OpenZeppelin/solidity-docgen/blob/master/src/config.ts) of solidity-docgen for the full list of configurable parameters.
9 changes: 5 additions & 4 deletions contracts/IPAccountImpl.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
Expand All @@ -13,10 +13,11 @@ import { IAccessController } from "./interfaces/IAccessController.sol";
import { IIPAccount } from "./interfaces/IIPAccount.sol";
import { MetaTx } from "./lib/MetaTx.sol";
import { Errors } from "./lib/Errors.sol";
import { IPAccountStorage } from "./IPAccountStorage.sol";

/// @title IPAccountImpl
/// @notice The Story Protocol's implementation of the IPAccount.
contract IPAccountImpl is IERC165, IIPAccount {
contract IPAccountImpl is IPAccountStorage, IIPAccount {
address public immutable accessController;

/// @notice Returns the IPAccount's internal nonce for transaction ordering.
Expand All @@ -38,12 +39,12 @@ contract IPAccountImpl is IERC165, IIPAccount {
/// @notice Checks if the contract supports a specific interface
/// @param interfaceId The interface identifier, as specified in ERC-165
/// @return bool is true if the contract supports the interface, false otherwise
function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
function supportsInterface(bytes4 interfaceId) public view override(IPAccountStorage, IERC165) returns (bool) {
return (interfaceId == type(IIPAccount).interfaceId ||
interfaceId == type(IERC6551Account).interfaceId ||
interfaceId == type(IERC1155Receiver).interfaceId ||
interfaceId == type(IERC721Receiver).interfaceId ||
interfaceId == type(IERC165).interfaceId);
super.supportsInterface(interfaceId));
}

/// @notice Returns the identifier of the non-fungible token which owns the account
Expand Down
61 changes: 61 additions & 0 deletions contracts/IPAccountStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import { IIPAccountStorage } from "./interfaces/IIPAccountStorage.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
/// @title IPAccount Storage
/// @dev Implements the IIPAccountStorage interface for managing IPAccount's state using a namespaced storage pattern.
/// Inherits all functionalities from IIPAccountStorage, providing concrete implementations for the interface's methods.
/// This contract allows Modules to store and retrieve data in a structured and conflict-free manner
/// by utilizing namespaces, where the default namespace is determined by the
/// `msg.sender` (the caller Module's address).
contract IPAccountStorage is ERC165, IIPAccountStorage {
using ShortStrings for *;

mapping(bytes32 => mapping(bytes32 => string)) public stringData;
mapping(bytes32 => mapping(bytes32 => bytes)) public bytesData;
mapping(bytes32 => mapping(bytes32 => bytes32)) public bytes32Data;
mapping(bytes32 => mapping(bytes32 => uint256)) public uint256Data;
mapping(bytes32 => mapping(bytes32 => address)) public addressData;
mapping(bytes32 => mapping(bytes32 => bool)) public boolData;

/// @inheritdoc IIPAccountStorage
function setBytes(bytes32 key, bytes calldata value) external {
bytesData[_toBytes32(msg.sender)][key] = value;
}
/// @inheritdoc IIPAccountStorage
function getBytes(bytes32 key) external view returns (bytes memory) {
return bytesData[_toBytes32(msg.sender)][key];
}
/// @inheritdoc IIPAccountStorage
function getBytes(bytes32 namespace, bytes32 key) external view returns (bytes memory) {
return bytesData[namespace][key];
}

/// @inheritdoc IIPAccountStorage
function setBytes32(bytes32 key, bytes32 value) external {
bytes32Data[_toBytes32(msg.sender)][key] = value;
}
/// @inheritdoc IIPAccountStorage
function getBytes32(bytes32 key) external view returns (bytes32) {
return bytes32Data[_toBytes32(msg.sender)][key];
}
/// @inheritdoc IIPAccountStorage
function getBytes32(bytes32 namespace, bytes32 key) external view returns (bytes32) {
return bytes32Data[namespace][key];
}

/// @notice ERC165 interface identifier for IIPAccountStorage
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) {
return interfaceId == type(IIPAccountStorage).interfaceId || super.supportsInterface(interfaceId);
}

function _toBytes32(string memory s) internal pure returns (bytes32) {
return ShortString.unwrap(s.toShortString());
}

function _toBytes32(address a) internal pure returns (bytes32) {
return bytes32(uint256(uint160(a)));
}
}
78 changes: 78 additions & 0 deletions contracts/governance/GovernableUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { Errors } from "../lib/Errors.sol";
import { IGovernance } from "../interfaces/governance/IGovernance.sol";
import { IGovernable } from "../interfaces/governance/IGovernable.sol";
import { GovernanceLib } from "../lib/GovernanceLib.sol";

/// @title Governable
/// @dev All contracts managed by governance should inherit from this contract.
abstract contract GovernableUpgradeable is IGovernable, Initializable {
/// @custom:storage-location erc7201:story-protocol.GovernableUpgradeable
/// @param governance The address of the governance.
struct GovernableUpgradeableStorage {
address governance;
}

// keccak256(abi.encode(uint256(keccak256("story-protocol.GovernableUpgradeable")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant GovernableUpgradeableStorageLocation =
0xaed547d8331715caab0800583ca79170ef3186de64f009413517d98c5b905c00;

/// @dev Ensures that the function is called by the protocol admin.
modifier onlyProtocolAdmin() {
GovernableUpgradeableStorage storage $ = _getGovernableUpgradeableStorage();
if (!IGovernance($.governance).hasRole(GovernanceLib.PROTOCOL_ADMIN, msg.sender)) {
revert Errors.Governance__OnlyProtocolAdmin();
}
_;
}

modifier whenNotPaused() {
GovernableUpgradeableStorage storage $ = _getGovernableUpgradeableStorage();
if (IGovernance($.governance).getState() == GovernanceLib.ProtocolState.Paused) {
revert Errors.Governance__ProtocolPaused();
}
_;
}

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function __GovernableUpgradeable_init(address governance_) internal {
if (governance_ == address(0)) revert Errors.Governance__ZeroAddress();
_getGovernableUpgradeableStorage().governance = governance_;
emit GovernanceUpdated(governance_);
}

/// @notice Sets a new governance address.
/// @param newGovernance The address of the new governance.
function setGovernance(address newGovernance) external onlyProtocolAdmin {
GovernableUpgradeableStorage storage $ = _getGovernableUpgradeableStorage();

if (newGovernance == address(0)) revert Errors.Governance__ZeroAddress();
if (!ERC165Checker.supportsInterface(newGovernance, type(IGovernance).interfaceId))
revert Errors.Governance__UnsupportedInterface("IGovernance");
if (IGovernance(newGovernance).getState() != IGovernance($.governance).getState())
revert Errors.Governance__InconsistentState();
$.governance = newGovernance;
emit GovernanceUpdated(newGovernance);
}

/// @notice Returns the current governance address.
/// @return governance The address of the current governance.
function getGovernance() external view returns (address) {
return _getGovernableUpgradeableStorage().governance;
}

function _getGovernableUpgradeableStorage() private pure returns (GovernableUpgradeableStorage storage $) {
assembly {
$.slot := GovernableUpgradeableStorageLocation
}
}
}
3 changes: 2 additions & 1 deletion contracts/interfaces/IIPAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.23;
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";
import { IIPAccountStorage } from "./IIPAccountStorage.sol";

/// @title IIPAccount
/// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard.
Expand All @@ -13,7 +14,7 @@ import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol";
/// IPAccount can interact with modules by making calls as a normal transaction sender.
/// This allows for seamless operations on the state and data of IP.
/// IPAccount is core identity for all actions.
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver {
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver, IIPAccountStorage {
/// @notice Emitted when a transaction is executed.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether sent.
Expand Down
Loading
Loading