Skip to content

Commit 09bfde6

Browse files
authored
GNS updated to work with ENS text records (#218)
* Update GNS to use ENS and compile * Update GNS according to comments from Ariel and Brandon * Add in GNS to enforce subgraph numbers through counter * Remove ENS contracts from repo, since validation is done in subgraph * Fix some GNS bugs and write tests * Fix deployment script for gns with 1 more arguement * Add in ENS interfaces to be in the npm package * Add back in name system to event signature
1 parent cb34880 commit 09bfde6

14 files changed

+623
-120
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ coverage/
1414
# Buidler cache
1515
cached/
1616

17+
# Ignore solc bin output
18+
bin/
19+
1720
# Others
1821
.privkey.txt
1922
.infurakey.txt
2023
.DS_Store
24+
.vscode

contracts/GNS.sol

Lines changed: 145 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,111 +2,201 @@ pragma solidity ^0.6.4;
22
pragma experimental ABIEncoderV2;
33

44
import "./Governed.sol";
5+
import "./erc1056/IEthereumDIDRegistry.sol";
56

67
/**
78
* @title GNS
89
* @dev The Graph Name System contract provides a decentralized namings system for subgraphs
9-
* used in the scope of the Graph Network. It translate subgraph names into
10-
* subgraphDeploymentID regarded as versions.
10+
* used in the scope of the Graph Network. It translates subgraph names into subgraph versions.
11+
* Each version is associated with a Subgraph Deployment. The contract no knowledge of human
12+
* readable names. All human readable names emitted in events.
1113
*/
1214
contract GNS is Governed {
13-
// -- Types --
14-
15-
enum RecordType { GNS }
15+
// -- State --
1616

17-
struct Record {
18-
address owner;
19-
bytes32 subgraphDeploymentID;
20-
RecordType nameSystem;
21-
}
17+
// graphAccountID => subgraphNumber => subgraphDeploymentID
18+
// graphAccountID = An ERC-1056 ID
19+
// subgraphNumber = Simply a number associated to a graph accounts deployed subgraph. This
20+
// is used to create a subgraphID (graphAccountID + subgraphNumber)
21+
// subgraphDeploymentID = The IPFS hash of the manifest of the subgraph
22+
mapping(address => mapping(uint256 => bytes32)) public subgraphs;
2223

23-
// -- State --
24+
// graphAccount => a counter of the accounts subgraph deployments
25+
mapping(address => uint256) public graphAccountSubgraphNumbers;
2426

25-
mapping(bytes32 => Record) public records;
27+
// ERC-1056 contract reference
28+
IEthereumDIDRegistry public erc1056Registry;
2629

2730
// -- Events --
2831

2932
/**
30-
* @dev Emitted when `owner` publish a `subgraphDeploymentID` version under subgraph `name`.
31-
* The event also attach `metadataHash` with extra information.
33+
* @dev Emitted when a `graph account` publishes a `subgraph` with a `version`.
34+
* Every time this event is emitted, indicates a new version has been created.
35+
* The event also emits a `metadataHash` with subgraph details and version details.
36+
* Name data is emitted, as well as the name system.
3237
*/
3338
event SubgraphPublished(
34-
string name,
35-
address owner,
39+
address graphAccount,
40+
uint256 subgraphNumber,
3641
bytes32 subgraphDeploymentID,
42+
uint256 nameSystem, // placeholder until we implement more than ENS
43+
bytes32 nameIdentifier,
44+
string name,
3745
bytes32 metadataHash
3846
);
3947

4048
/**
41-
* @dev Emitted when subgraph `nameHash` is unpublished by its owner.
49+
* @dev Emitted when a graph account deprecated one of their subgraphs
4250
*/
43-
event SubgraphUnpublished(bytes32 nameHash);
51+
event SubgraphDeprecated(address graphAccount, uint256 subgraphNumber);
4452

4553
/**
46-
* @dev Emitted when subgraph `nameHash` is transferred to new owner.
47-
*/
48-
event SubgraphTransferred(bytes32 nameHash, address from, address to);
49-
50-
modifier onlyRecordOwner(bytes32 _nameHash) {
51-
require(msg.sender == records[_nameHash].owner, "GNS: Only record owner can call");
54+
@dev Modifier that allows a function to be called by owner of a graph account. Only owner can call
55+
@param _graphAccount Address of the graph account
56+
*/
57+
modifier onlyGraphAccountOwner(address _graphAccount) {
58+
address graphAccountOwner = erc1056Registry.identityOwner(_graphAccount);
59+
require(graphAccountOwner == msg.sender, "GNS: Only graph account owner can call");
5260
_;
5361
}
5462

5563
/**
5664
* @dev Contract Constructor.
5765
* @param _governor Owner address of this contract
66+
* @param _didRegistry Address of the Ethereum DID registry
5867
*/
59-
constructor(address _governor) public Governed(_governor) {}
68+
constructor(address _governor, address _didRegistry) public Governed(_governor) {
69+
erc1056Registry = IEthereumDIDRegistry(_didRegistry);
70+
}
6071

6172
/**
62-
* @dev Publish a version using `subgraphDeploymentID` under a subgraph..
63-
* @param _name Name of the subgraph
64-
* @param _subgraphDeploymentID SubgraphDeployment to link to the subgraph
65-
* @param _metadataHash IPFS hash linked to the metadata
73+
* @dev Allows a graph account to publish a new subgraph, which means a new subgraph number
74+
* will be allocated. It then will call publish version. Subsequent versions can be created
75+
* by calling publishVersion() directly.
76+
* @param _graphAccount Account that is publishing the subgraph
77+
* @param _subgraphDeploymentID Subgraph deployment ID of the version, linked to the name
78+
* @param _nameIdentifier The value used to look up ownership in the naming system
79+
* @param _name Name of the subgraph, from any valid system
80+
* @param _metadataHash IPFS hash for the subgraph, and subgraph version metadata
6681
*/
67-
function publish(
82+
function publishNewSubgraph(
83+
address _graphAccount,
84+
bytes32 _subgraphDeploymentID,
85+
bytes32 _nameIdentifier,
6886
string calldata _name,
87+
bytes32 _metadataHash
88+
) external onlyGraphAccountOwner(_graphAccount) {
89+
uint256 subgraphNumber = graphAccountSubgraphNumbers[_graphAccount];
90+
publishVersion(
91+
_graphAccount,
92+
subgraphNumber,
93+
_subgraphDeploymentID,
94+
_nameIdentifier,
95+
_name,
96+
_metadataHash
97+
);
98+
graphAccountSubgraphNumbers[_graphAccount]++;
99+
}
100+
101+
/**
102+
* @dev Allows a graph account to publish a subgraph, with a version, a name, and metadata
103+
* Graph account must be owner on their ERC-1056 identity
104+
* Graph account must own the name of the name system they are linking to the subgraph
105+
* Version is derived from the occurance of SubgraphPublish being emitted. i.e. version 0
106+
* is the first time the event is emitted for the graph account and subgraph number
107+
* combination.
108+
* @param _graphAccount Account that is publishing the subgraph
109+
* @param _subgraphNumber Subgraph number for the account
110+
* @param _subgraphDeploymentID Subgraph deployment ID of the version, linked to the name
111+
* @param _nameIdentifier The value used to look up ownership in the naming system
112+
* @param _name Name of the subgraph, from any valid system
113+
* @param _metadataHash IPFS hash for the subgraph, and subgraph version metadata
114+
*/
115+
function publishNewVersion(
116+
address _graphAccount,
117+
uint256 _subgraphNumber,
69118
bytes32 _subgraphDeploymentID,
119+
bytes32 _nameIdentifier,
120+
string calldata _name,
70121
bytes32 _metadataHash
71-
) external {
72-
address owner = msg.sender;
73-
bytes32 nameHash = keccak256(bytes(_name));
122+
) external onlyGraphAccountOwner(_graphAccount) {
74123
require(
75-
!isReserved(nameHash) || records[nameHash].owner == owner,
76-
"GNS: Record reserved, only record owner can publish"
124+
isPublished(_graphAccount, _subgraphNumber) || // Hasn't been created yet
125+
_subgraphNumber < graphAccountSubgraphNumbers[_graphAccount], // Was created, but deprecated
126+
"GNS: Cant publish a version directly for a subgraph that wasnt created yet"
77127
);
78128

79-
records[nameHash] = Record(owner, _subgraphDeploymentID, RecordType.GNS);
80-
emit SubgraphPublished(_name, owner, _subgraphDeploymentID, _metadataHash);
129+
publishVersion(
130+
_graphAccount,
131+
_subgraphNumber,
132+
_subgraphDeploymentID,
133+
_nameIdentifier,
134+
_name,
135+
_metadataHash
136+
);
81137
}
82138

83139
/**
84-
* @dev Unpublish a subgraph name. Can only be done by the owner.
85-
* @param _nameHash Keccak256 hash of the subgraph name
140+
* @dev Internal function used by both external publishing functions
141+
* @param _graphAccount Account that is publishing the subgraph
142+
* @param _subgraphNumber Subgraph number for the account
143+
* @param _subgraphDeploymentID Subgraph deployment ID of the version, linked to the name
144+
* @param _nameIdentifier The value used to look up ownership in the naming system
145+
* @param _name Name of the subgraph, from any valid system
146+
* @param _metadataHash IPFS hash for the subgraph, and subgraph version metadata
86147
*/
87-
function unpublish(bytes32 _nameHash) external onlyRecordOwner(_nameHash) {
88-
delete records[_nameHash];
89-
emit SubgraphUnpublished(_nameHash);
148+
function publishVersion(
149+
address _graphAccount,
150+
uint256 _subgraphNumber,
151+
bytes32 _subgraphDeploymentID,
152+
bytes32 _nameIdentifier,
153+
string memory _name,
154+
bytes32 _metadataHash
155+
) internal {
156+
require(_subgraphDeploymentID != 0, "GNS: Cannot set to 0 in publish");
157+
158+
// Stores a subgraph deployment ID, which indicates a version has been created
159+
subgraphs[_graphAccount][_subgraphNumber] = _subgraphDeploymentID;
160+
// Emit version and name data
161+
emit SubgraphPublished(
162+
_graphAccount,
163+
_subgraphNumber,
164+
_subgraphDeploymentID,
165+
0,
166+
_nameIdentifier,
167+
_name,
168+
_metadataHash
169+
);
90170
}
91171

92172
/**
93-
* @dev Tranfer the subgraph name to a new owner.
94-
* @param _nameHash Keccak256 hash of the subgraph name
95-
* @param _to Address of the new owner
173+
* @dev Deprecate a subgraph. Can only be done by the erc-1506 identity owner.
174+
* @param _graphAccount Account that is publishing the subgraph
175+
* @param _subgraphNumber Subgraph number for the account
96176
*/
97-
function transfer(bytes32 _nameHash, address _to) external onlyRecordOwner(_nameHash) {
98-
require(_to != address(0), "GNS: Cannot transfer to empty address");
99-
require(records[_nameHash].owner != _to, "GNS: Cannot transfer to itself");
100-
records[_nameHash].owner = _to;
101-
emit SubgraphTransferred(_nameHash, msg.sender, _to);
177+
function deprecate(address _graphAccount, uint256 _subgraphNumber)
178+
external
179+
onlyGraphAccountOwner(_graphAccount)
180+
{
181+
require(
182+
isPublished(_graphAccount, _subgraphNumber),
183+
"GNS: Cannot deprecate a subgraph which does not exist"
184+
);
185+
delete subgraphs[_graphAccount][_subgraphNumber];
186+
emit SubgraphDeprecated(_graphAccount, _subgraphNumber);
102187
}
103188

104189
/**
105-
* @dev Return whether a subgraph name is registed or not.
106-
* @param _nameHash Keccak256 hash of the subgraph name
107-
* @return Return true if subgraph name exists
190+
* @dev Return whether a subgraph name is published.
191+
* @param _graphAccount Account being checked
192+
* @param _subgraphNumber Subgraph number being checked for publishing
193+
* @return Return true if subgraph is currently published
108194
*/
109-
function isReserved(bytes32 _nameHash) public view returns (bool) {
110-
return records[_nameHash].owner != address(0);
195+
function isPublished(address _graphAccount, uint256 _subgraphNumber)
196+
public
197+
view
198+
returns (bool)
199+
{
200+
return subgraphs[_graphAccount][_subgraphNumber] != 0;
111201
}
112202
}

contracts/ens/IENS.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pragma solidity ^0.6.4;
2+
3+
// Needed for abi and typechain in the npm package
4+
interface IENS {
5+
function owner(bytes32 node) external view returns (address);
6+
}

contracts/ens/IPublicResolver.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pragma solidity ^0.6.4;
2+
3+
// Needed for abi and typechain in the npm package
4+
interface IPublicResolver {
5+
function text(bytes32 node, string calldata key) external view returns (string memory);
6+
function setText(bytes32 node, string calldata key, string calldata value) external;
7+
}

0 commit comments

Comments
 (0)