Skip to content

Commit

Permalink
chore: update contracts, readme and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
b00ste committed Aug 2, 2024
1 parent 65966a1 commit 5b180fb
Show file tree
Hide file tree
Showing 21 changed files with 148 additions and 79 deletions.
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
"packages/lsp20-contracts": "0.15.0",
"packages/lsp23-contracts": "0.15.0",
"packages/lsp25-contracts": "0.15.0",
"packages/lsp26-contracts": "0.15.0",
"packages/universalprofile-contracts": "0.15.0"
}
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/lsp-smart-contracts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ import {
INTERFACE_ID_LSP20CallVerifier,
} from '@lukso/lsp20-contracts';
import { INTERFACE_ID_LSP25 } from '@lukso/lsp25-contracts';
import { INTERFACE_ID_LSP26 } from '@lukso/lsp26-contracts';

// LSP1 Type IDs of each LSP
import { LSP0_TYPE_IDS } from '@lukso/lsp0-contracts';
import { LSP7_TYPE_IDS } from '@lukso/lsp7-contracts';
import { LSP8_TYPE_IDS } from '@lukso/lsp8-contracts';
import { LSP9_TYPE_IDS } from '@lukso/lsp9-contracts';
import { LSP14_TYPE_IDS } from '@lukso/lsp14-contracts';
import { LSP26_TYPE_IDS } from '@lukso/lsp26-contracts';

// ERC725Y Data Keys of each LSP
import { LSP1DataKeys } from '@lukso/lsp1-contracts';
Expand Down Expand Up @@ -117,6 +119,7 @@ export const INTERFACE_IDS = {
LSP20CallVerifier: INTERFACE_ID_LSP20CallVerifier,
LSP11BasicSocialRecovery: '0x049a28f1',
LSP25ExecuteRelayCall: INTERFACE_ID_LSP25,
LSP26FollowingSystem: INTERFACE_ID_LSP26,
};

// ERC725Y
Expand Down Expand Up @@ -147,4 +150,5 @@ export const LSP1_TYPE_IDS = {
...LSP8_TYPE_IDS,
...LSP9_TYPE_IDS,
...LSP14_TYPE_IDS,
...LSP26_TYPE_IDS,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.17;

import {
ILSP26FollowingSystem
} from "@lukso/lsp26-contracts/contracts/ILSP26FollowingSystem.sol";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;

import "@lukso/lsp26-contracts/contracts/LSP26Constants.sol";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.4;

import "@lukso/lsp26-contracts/contracts/LSP26Errors.sol";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.17;

import {
LSP26FollowingSystem
} from "@lukso/lsp26-contracts/contracts/LSP26FollowingSystem.sol";
16 changes: 16 additions & 0 deletions packages/lsp-smart-contracts/contracts/Mocks/ERC165Interfaces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ import {
import {
ILSP25ExecuteRelayCall as ILSP25
} from "@lukso/lsp25-contracts/contracts/ILSP25ExecuteRelayCall.sol";
import {
ILSP26FollowingSystem as ILSP26
} from "@lukso/lsp26-contracts/contracts/ILSP26FollowingSystem.sol";

// constants
import {
Expand Down Expand Up @@ -102,6 +105,9 @@ import {
import {
_INTERFACEID_LSP25
} from "@lukso/lsp25-contracts/contracts/LSP25Constants.sol";
import {
_INTERFACEID_LSP26
} from "@lukso/lsp26-contracts/contracts/LSP26Constants.sol";

// libraries
import {
Expand Down Expand Up @@ -302,6 +308,16 @@ contract CalculateLSPInterfaces {

return interfaceId;
}

function calculateInterfaceLSP26() public pure returns (bytes4) {
bytes4 interfaceId = type(ILSP26).interfaceId;
require(
interfaceId == _INTERFACEID_LSP26,
"hardcoded _INTERFACEID_LSP26 does not match type(ILSP26).interfaceId"
);

return interfaceId;
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/lsp-smart-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"@lukso/lsp20-contracts": "~0.15.0",
"@lukso/lsp23-contracts": "~0.15.0",
"@lukso/lsp25-contracts": "~0.15.0",
"@lukso/lsp26-contracts": "~0.15.0",
"@lukso/lsp3-contracts": "~0.15.0",
"@lukso/lsp4-contracts": "~0.15.0",
"@lukso/lsp5-contracts": "~0.15.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ describe('Calculate LSP interfaces', () => {
const result = await contract.calculateInterfaceLSP25ExecuteRelayCall();
expect(result).to.equal(INTERFACE_IDS.LSP25ExecuteRelayCall);
});

it('LSP26FollowingSystem', async () => {
const result = await contract.calculateInterfaceLSP26();
expect(result).to.equal(INTERFACE_IDS.LSP26FollowingSystem);
});
});

describe('Calculate ERC interfaces', () => {
Expand Down
50 changes: 8 additions & 42 deletions packages/lsp26-contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,17 @@
# LSP Package Template
# LSP26 Following System · [![npm version](https://img.shields.io/npm/v/@lukso/lsp26-contracts.svg?style=flat)](https://www.npmjs.com/package/@lukso/lsp26-contracts)

This project can be used as a skeleton to build a package for a LSP implementation in Solidity (LUKSO Standard Proposal)
Package for the LSP26 Following System standard.

It is based on Hardhat.

## How to setup a LSP as a package?

1. Copy the `template/` folder and paste it under the `packages/` folder. Then rename this `template/` folder that you copied with the LSP name.

You can do so either:

- manually, by copying the folder and pasting it inside `packages` and then renaming it.
or
- by running the following command from the root of the repository.
## Installation

```bash
cp -r template packages/lsp-name
npm i @lukso/lsp26-contracts
```

2. Update the `"name"` and `"description"` field inside the `package.json` for this LSP package you just created.

3. Setup the dependencies

If this LSP uses external dependencies like `@openzeppelin/contracts`, put them under `dependencies` with the version number.

```json
"@openzeppelin/contracts": "^4.9.3"
```
## Available Constants & Types

If this LSP uses other LSP as dependencies, put each LSP dependency as shown below. This will use the current code in the package:
The `@lukso/lsp26-contracts` npm package contains useful constants such as InterfaceIds, and specific constants related to the LSP26 Standard. You can import and access them as follow:

```json
"@lsp2": "*"
```js
import { INTERFACE_ID_LSP26, LSP26_TYPE_IDS } from "@lukso/lsp26-contracts";
```

4. Setup the npm commands for linting, building, testing, etc... under the `"scripts"` in the `package.json`

5. Test that all commands you setup run successfully

By running the commands below, your LSP package should come up in the list of packages that Turbo is running this command for.

```bash
turbo build
turbo lint
turbo lint:solidity
turbo test
turbo test:foundry
```

6. Finally update the relevant information in the `README.md` file in the folder of the newly created package, such as the title at the top, some description, etc...
2 changes: 1 addition & 1 deletion packages/lsp26-contracts/build.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineBuildConfig } from 'unbuild';

export default defineBuildConfig({
entries: ['./constants'],
entries: ['./index'],
declaration: 'compatible', // generate .d.ts files
rollup: {
emitCJS: true,
Expand Down
11 changes: 8 additions & 3 deletions packages/lsp26-contracts/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// Define your constants to be exported here
export const INTERFACE_ID_LSP26 = '0x2b299cea';

// example
export const LSPN_CONSTANT_VALUE = 123;
export const LSP26_TYPE_IDS = {
// keccak256('LSP26FollowerSystem_FollowNotification')
_TYPEID_LSP26_FOLLOW: '0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a',

// keccak256('LSP26FollowerSystem_UnfollowNotification')
_TYPEID_LSP26_UNFOLLOW: '0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f',
};
8 changes: 4 additions & 4 deletions packages/lsp26-contracts/contracts/ILSP26FollowingSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ interface ILSP26FollowingSystem {
event Unfollow(address unfollower, address addr);

/// @notice Follow an specific address.
/// @custom:events {Follow} event when following an address.
/// @param addr The address to start following.
/// @custom:events {Follow} event when following an address.
function follow(address addr) external;

/// @notice Follow a list of addresses.
/// @custom:events {Follow} event when following each address in the list.
/// @param addresses The list of addresses to follow.
/// @custom:events {Follow} event when following each address in the list.
function followBatch(address[] memory addresses) external;

/// @notice Unfollow a specific address.
/// @custom:events {Unfollow} event when unfollowing an address.
/// @param addr The address to stop following.
/// @custom:events {Unfollow} event when unfollowing an address.
function unfollow(address addr) external;

/// @notice Unfollow a list of addresses.
/// @custom:events {Follow} event when unfollowing each address in the list.
/// @param addresses The list of addresses to unfollow.
/// @custom:events {Follow} event when unfollowing each address in the list.
function unfollowBatch(address[] memory addresses) external;

/// @notice Check if an address is following a specific address.
Expand Down
2 changes: 2 additions & 0 deletions packages/lsp26-contracts/contracts/LSP26Constants.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.17;

bytes4 constant _INTERFACEID_LSP26 = 0x2b299cea;

// keccak256('LSP26FollowerSystem_FollowNotification')
bytes32 constant _TYPEID_LSP26_FOLLOW = 0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a;

Expand Down
2 changes: 0 additions & 2 deletions packages/lsp26-contracts/contracts/LSP26Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ pragma solidity ^0.8.17;

error LSP26CannotSelfFollow();

error LSP26CannotSelfUnfollow();

error LSP26AlreadyFollowing(address addr);

error LSP26NotFollowing(address addr);
41 changes: 20 additions & 21 deletions packages/lsp26-contracts/contracts/LSP26FollowingSystem.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.17;

// interafces
// interfaces
import {ILSP26FollowingSystem} from "./ILSP26FollowingSystem.sol";
import {
ILSP1UniversalReceiver
Expand All @@ -27,7 +27,6 @@ import {
// errors
import {
LSP26CannotSelfFollow,
LSP26CannotSelfUnfollow,
LSP26AlreadyFollowing,
LSP26NotFollowing
} from "./LSP26Errors.sol";
Expand All @@ -46,7 +45,7 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {

// @inheritdoc ILSP26FollowingSystem
function followBatch(address[] memory addresses) public {
for (uint256 index = 0; index < addresses.length; index++) {
for (uint256 index = 0; index < addresses.length; ++index) {
_follow(addresses[index]);
}
}
Expand All @@ -58,7 +57,7 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {

// @inheritdoc ILSP26FollowingSystem
function unfollowBatch(address[] memory addresses) public {
for (uint256 index = 0; index < addresses.length; index++) {
for (uint256 index = 0; index < addresses.length; ++index) {
_unfollow(addresses[index]);
}
}
Expand Down Expand Up @@ -87,9 +86,11 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {
uint256 startIndex,
uint256 endIndex
) public view returns (address[] memory) {
address[] memory followings = new address[](endIndex - startIndex);
uint256 sliceLength = endIndex - startIndex;

for (uint256 index = 0; index < endIndex - startIndex; index++) {
address[] memory followings = new address[](sliceLength);

for (uint256 index = 0; index < sliceLength; ++index) {
followings[index] = _followingsOf[addr].at(startIndex + index);
}

Expand All @@ -102,9 +103,11 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {
uint256 startIndex,
uint256 endIndex
) public view returns (address[] memory) {
address[] memory followers = new address[](endIndex - startIndex);
uint256 sliceLength = endIndex - startIndex;

address[] memory followers = new address[](sliceLength);

for (uint256 index = 0; index < endIndex - startIndex; index++) {
for (uint256 index = 0; index < sliceLength; ++index) {
followers[index] = _followersOf[addr].at(startIndex + index);
}

Expand All @@ -116,13 +119,16 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {
revert LSP26CannotSelfFollow();
}

if (_followingsOf[msg.sender].contains(addr)) {
bool isAdded = _followingsOf[msg.sender].add(addr);

if (!isAdded) {
revert LSP26AlreadyFollowing(addr);
}

_followingsOf[msg.sender].add(addr);
_followersOf[addr].add(msg.sender);

emit Follow(msg.sender, addr);

if (addr.supportsERC165InterfaceUnchecked(_INTERFACEID_LSP1)) {
// solhint-disable no-empty-blocks
try
Expand All @@ -131,24 +137,20 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {
abi.encodePacked(msg.sender)
)
{} catch {}
// returns (bytes memory data) {} catch {}
}

emit Follow(msg.sender, addr);
}

function _unfollow(address addr) internal {
if (msg.sender == addr) {
revert LSP26CannotSelfUnfollow();
}
bool isRemoved = _followingsOf[msg.sender].remove(addr);

if (!_followingsOf[msg.sender].contains(addr)) {
if (!isRemoved) {
revert LSP26NotFollowing(addr);
}

_followingsOf[msg.sender].remove(addr);
_followersOf[addr].remove(msg.sender);

emit Unfollow(msg.sender, addr);

if (addr.supportsERC165InterfaceUnchecked(_INTERFACEID_LSP1)) {
// solhint-disable no-empty-blocks
try
Expand All @@ -157,9 +159,6 @@ contract LSP26FollowingSystem is ILSP26FollowingSystem {
abi.encodePacked(msg.sender)
)
{} catch {}
// returns (bytes memory data) {} catch {}
}

emit Unfollow(msg.sender, addr);
}
}
20 changes: 20 additions & 0 deletions packages/lsp26-contracts/contracts/mock/RevertOnFollow.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.17;

// interfaces
import {
ILSP1UniversalReceiver
} from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";

contract RevertOnFollow is ILSP1UniversalReceiver {
function supportsInterface(bytes4) external pure returns (bool) {
return true;
}

function universalReceiver(
bytes32,
bytes memory
) external payable returns (bytes memory) {
revert("Block LSP1 notifications");
}
}
Loading

0 comments on commit 5b180fb

Please sign in to comment.