epistery 1.5.2 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/build-info/5a987fca94856a824565c891c6bdbcbd.json +1 -0
- package/artifacts/contracts/ICreditAccount.sol/ICreditAccount.dbg.json +4 -0
- package/artifacts/contracts/ICreditAccount.sol/ICreditAccount.json +67 -0
- package/artifacts/contracts/IUserRegistry.sol/IUserRegistry.dbg.json +4 -0
- package/artifacts/contracts/IUserRegistry.sol/IUserRegistry.json +72 -0
- package/contracts/ICreditAccount.sol +48 -0
- package/contracts/IUserRegistry.sol +34 -0
- package/docs/IdentityNaming.md +46 -39
- package/package.json +1 -1
- package/routes/whitelist/index.mjs +9 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"5a987fca94856a824565c891c6bdbcbd","_format":"hh-sol-build-info-1","solcVersion":"0.8.27","solcLongVersion":"0.8.27+commit.40a35a09","input":{"language":"Solidity","sources":{"contracts/IAddressNaming.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title IAddressNaming\n * @notice Canonical interface for resolving identity names from addresses.\n *\n * Names belong to the address itself, not to any (address, list) join.\n * Roles (\"owner\", \"admin\", \"read\", ...) remain on whitelist / ACL entries;\n * names do not. The same address may carry different per-list handles in\n * legacy WhitelistEntry.name fields, but its identity name lives behind\n * this interface.\n *\n * Implementations may be multi-tenant or single-tenant:\n * - Multi-tenant (e.g. epistery Agent.sol): the read accepts an\n * ownerAddress scope; writes are keyed by msg.sender.\n * - Single-tenant (e.g. epistery-host DomainAgent.sol): the read's\n * ownerAddress argument is accepted on the signature for ABI\n * compatibility but ignored; writes are admin-gated.\n *\n * Off-chain consumers (e.g. epistery's Utils.ResolveAddressName,\n * Utils.SetAddressName) hold against this interface, so they work\n * uniformly against either implementation without branching on\n * contract type.\n */\ninterface IAddressNaming {\n /**\n * @notice Set the human-readable name for an address.\n * @param addr The address to name\n * @param name The name string; empty string clears\n */\n function setAddressName(address addr, string memory name) external;\n\n /**\n * @notice Resolve an address to its name.\n * @param ownerAddress The naming-scope owner; ignored by single-tenant\n * implementations, used by multi-tenant ones\n * @param addr The address to resolve\n * @return The name, or empty string if unset\n */\n function getAddressName(address ownerAddress, address addr) external view returns (string memory);\n}\n"},"contracts/ICreditAccount.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title ICreditAccount\n * @notice Canonical interface for credit-bearing user accounts.\n *\n * Signatures match Steven's `UniversalTeamRegistryV4` on Polygon mainnet\n * (`0x83B25fDD25516057AaaAf8027464C8bbb2f91d5B`) so that contract can\n * declare conformance without renaming any existing methods.\n *\n * Implementations decide the conversion between native token (POL/ETH)\n * and credits. UniversalTeamRegistryV4 uses 1 POL = 1,000,000 credits.\n *\n * The user-facing surface is deposit + read. Implementation-private\n * operations (funding specific child contracts like Secrets or KeyVaults,\n * setting rate tables, etc.) are NOT part of this interface — they're\n * authorization-gated internals.\n *\n * Epistery does not yet implement credit accounting. This interface is\n * declared on the epistery side as the cross-system spec; epistery\n * contracts may adopt it later, or epistery-host may delegate credit\n * operations to rootz-v6's deployed Registry.\n */\ninterface ICreditAccount {\n /**\n * @notice Emitted when credits are added to an account.\n * @param user The user whose balance increased\n * @param amount The credit amount added\n */\n event CreditsDeposited(address indexed user, uint256 amount);\n\n /**\n * @notice Deposit credits for `user`, paying with native token.\n * The native token amount is `msg.value`; implementations convert\n * to credit units according to their rate table.\n * @param user The account to credit\n * @param amount The credit amount to deposit\n */\n function depositCredits(address user, uint256 amount) external payable;\n\n /**\n * @notice Read the current credit balance for `user`.\n * @param user The account to read\n * @return The current credit balance\n */\n function getUserCredits(address user) external view returns (uint256);\n}\n"},"contracts/IUserRegistry.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IAddressNaming.sol\";\n\n/**\n * @title IUserRegistry\n * @notice Canonical interface for \"I am a user registry\" — the kind of\n * service that knows which addresses belong to people on this system.\n *\n * Carries IAddressNaming as a base because name resolution is a user-registry\n * responsibility. Adds a single membership predicate; implementations decide\n * what \"registered\" means in their domain:\n *\n * - epistery Agent.sol / DomainAgent.sol: addresses listed on any\n * whitelist / ACL under this contract.\n * - rootz-v6 UniversalTeamRegistryV4: addresses with a credit account,\n * authorized factory, or team membership.\n * - rootz-v6 IdentityContractV3: addresses authorized as rivets on this\n * identity.\n *\n * Off-chain code that wants to ask \"does this system know this address?\"\n * holds against this interface and gets a uniform answer.\n */\ninterface IUserRegistry is IAddressNaming {\n /**\n * @notice True if this registry has a record of the address.\n * \"Record\" is implementation-defined — membership, identity,\n * credit account, rivet registration, etc.\n * @param addr The address to check\n * @return True if the address is known to this registry\n */\n function isRegistered(address addr) external view returns (bool);\n}\n"}},"settings":{"optimizer":{"enabled":true,"runs":200},"evmVersion":"paris","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}}}},"output":{"sources":{"contracts/IAddressNaming.sol":{"ast":{"absolutePath":"contracts/IAddressNaming.sol","exportedSymbols":{"IAddressNaming":[21]},"id":22,"license":"MIT","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"32:23:0"},{"abstract":false,"baseContracts":[],"canonicalName":"IAddressNaming","contractDependencies":[],"contractKind":"interface","documentation":{"id":2,"nodeType":"StructuredDocumentation","src":"57:1023:0","text":" @title IAddressNaming\n @notice Canonical interface for resolving identity names from addresses.\n Names belong to the address itself, not to any (address, list) join.\n Roles (\"owner\", \"admin\", \"read\", ...) remain on whitelist / ACL entries;\n names do not. The same address may carry different per-list handles in\n legacy WhitelistEntry.name fields, but its identity name lives behind\n this interface.\n Implementations may be multi-tenant or single-tenant:\n - Multi-tenant (e.g. epistery Agent.sol): the read accepts an\n ownerAddress scope; writes are keyed by msg.sender.\n - Single-tenant (e.g. epistery-host DomainAgent.sol): the read's\n ownerAddress argument is accepted on the signature for ABI\n compatibility but ignored; writes are admin-gated.\n Off-chain consumers (e.g. epistery's Utils.ResolveAddressName,\n Utils.SetAddressName) hold against this interface, so they work\n uniformly against either implementation without branching on\n contract type."},"fullyImplemented":false,"id":21,"linearizedBaseContracts":[21],"name":"IAddressNaming","nameLocation":"1091:14:0","nodeType":"ContractDefinition","nodes":[{"documentation":{"id":3,"nodeType":"StructuredDocumentation","src":"1112:165:0","text":" @notice Set the human-readable name for an address.\n @param addr The address to name\n @param name The name string; empty string clears"},"functionSelector":"3037c5ad","id":10,"implemented":false,"kind":"function","modifiers":[],"name":"setAddressName","nameLocation":"1291:14:0","nodeType":"FunctionDefinition","parameters":{"id":8,"nodeType":"ParameterList","parameters":[{"constant":false,"id":5,"mutability":"mutable","name":"addr","nameLocation":"1314:4:0","nodeType":"VariableDeclaration","scope":10,"src":"1306:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":4,"name":"address","nodeType":"ElementaryTypeName","src":"1306:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":7,"mutability":"mutable","name":"name","nameLocation":"1334:4:0","nodeType":"VariableDeclaration","scope":10,"src":"1320:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":6,"name":"string","nodeType":"ElementaryTypeName","src":"1320:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1305:34:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[],"src":"1348:0:0"},"scope":21,"src":"1282:67:0","stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"documentation":{"id":11,"nodeType":"StructuredDocumentation","src":"1355:283:0","text":" @notice Resolve an address to its name.\n @param ownerAddress The naming-scope owner; ignored by single-tenant\n implementations, used by multi-tenant ones\n @param addr The address to resolve\n @return The name, or empty string if unset"},"functionSelector":"b715bb74","id":20,"implemented":false,"kind":"function","modifiers":[],"name":"getAddressName","nameLocation":"1652:14:0","nodeType":"FunctionDefinition","parameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":13,"mutability":"mutable","name":"ownerAddress","nameLocation":"1675:12:0","nodeType":"VariableDeclaration","scope":20,"src":"1667:20:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":12,"name":"address","nodeType":"ElementaryTypeName","src":"1667:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":15,"mutability":"mutable","name":"addr","nameLocation":"1697:4:0","nodeType":"VariableDeclaration","scope":20,"src":"1689:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":14,"name":"address","nodeType":"ElementaryTypeName","src":"1689:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1666:36:0"},"returnParameters":{"id":19,"nodeType":"ParameterList","parameters":[{"constant":false,"id":18,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":20,"src":"1726:13:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":17,"name":"string","nodeType":"ElementaryTypeName","src":"1726:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1725:15:0"},"scope":21,"src":"1643:98:0","stateMutability":"view","virtual":false,"visibility":"external"}],"scope":22,"src":"1081:662:0","usedErrors":[],"usedEvents":[]}],"src":"32:1712:0"},"id":0},"contracts/ICreditAccount.sol":{"ast":{"absolutePath":"contracts/ICreditAccount.sol","exportedSymbols":{"ICreditAccount":[48]},"id":49,"license":"MIT","nodeType":"SourceUnit","nodes":[{"id":23,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"32:23:1"},{"abstract":false,"baseContracts":[],"canonicalName":"ICreditAccount","contractDependencies":[],"contractKind":"interface","documentation":{"id":24,"nodeType":"StructuredDocumentation","src":"57:968:1","text":" @title ICreditAccount\n @notice Canonical interface for credit-bearing user accounts.\n Signatures match Steven's `UniversalTeamRegistryV4` on Polygon mainnet\n (`0x83B25fDD25516057AaaAf8027464C8bbb2f91d5B`) so that contract can\n declare conformance without renaming any existing methods.\n Implementations decide the conversion between native token (POL/ETH)\n and credits. UniversalTeamRegistryV4 uses 1 POL = 1,000,000 credits.\n The user-facing surface is deposit + read. Implementation-private\n operations (funding specific child contracts like Secrets or KeyVaults,\n setting rate tables, etc.) are NOT part of this interface — they're\n authorization-gated internals.\n Epistery does not yet implement credit accounting. This interface is\n declared on the epistery side as the cross-system spec; epistery\n contracts may adopt it later, or epistery-host may delegate credit\n operations to rootz-v6's deployed Registry."},"fullyImplemented":false,"id":48,"linearizedBaseContracts":[48],"name":"ICreditAccount","nameLocation":"1036:14:1","nodeType":"ContractDefinition","nodes":[{"anonymous":false,"documentation":{"id":25,"nodeType":"StructuredDocumentation","src":"1057:169:1","text":" @notice Emitted when credits are added to an account.\n @param user The user whose balance increased\n @param amount The credit amount added"},"eventSelector":"39a4ec3b6d79868398fdc7602609ac7bba0e4a84df0ec6ff2007fdf0691431c7","id":31,"name":"CreditsDeposited","nameLocation":"1237:16:1","nodeType":"EventDefinition","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":27,"indexed":true,"mutability":"mutable","name":"user","nameLocation":"1270:4:1","nodeType":"VariableDeclaration","scope":31,"src":"1254:20:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":26,"name":"address","nodeType":"ElementaryTypeName","src":"1254:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":29,"indexed":false,"mutability":"mutable","name":"amount","nameLocation":"1284:6:1","nodeType":"VariableDeclaration","scope":31,"src":"1276:14:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":28,"name":"uint256","nodeType":"ElementaryTypeName","src":"1276:7:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1253:38:1"},"src":"1231:61:1"},{"documentation":{"id":32,"nodeType":"StructuredDocumentation","src":"1298:296:1","text":" @notice Deposit credits for `user`, paying with native token.\n The native token amount is `msg.value`; implementations convert\n to credit units according to their rate table.\n @param user The account to credit\n @param amount The credit amount to deposit"},"functionSelector":"1409f160","id":39,"implemented":false,"kind":"function","modifiers":[],"name":"depositCredits","nameLocation":"1608:14:1","nodeType":"FunctionDefinition","parameters":{"id":37,"nodeType":"ParameterList","parameters":[{"constant":false,"id":34,"mutability":"mutable","name":"user","nameLocation":"1631:4:1","nodeType":"VariableDeclaration","scope":39,"src":"1623:12:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":33,"name":"address","nodeType":"ElementaryTypeName","src":"1623:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":36,"mutability":"mutable","name":"amount","nameLocation":"1645:6:1","nodeType":"VariableDeclaration","scope":39,"src":"1637:14:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":35,"name":"uint256","nodeType":"ElementaryTypeName","src":"1637:7:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1622:30:1"},"returnParameters":{"id":38,"nodeType":"ParameterList","parameters":[],"src":"1669:0:1"},"scope":48,"src":"1599:71:1","stateMutability":"payable","virtual":false,"visibility":"external"},{"documentation":{"id":40,"nodeType":"StructuredDocumentation","src":"1676:151:1","text":" @notice Read the current credit balance for `user`.\n @param user The account to read\n @return The current credit balance"},"functionSelector":"81b26dda","id":47,"implemented":false,"kind":"function","modifiers":[],"name":"getUserCredits","nameLocation":"1841:14:1","nodeType":"FunctionDefinition","parameters":{"id":43,"nodeType":"ParameterList","parameters":[{"constant":false,"id":42,"mutability":"mutable","name":"user","nameLocation":"1864:4:1","nodeType":"VariableDeclaration","scope":47,"src":"1856:12:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":41,"name":"address","nodeType":"ElementaryTypeName","src":"1856:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1855:14:1"},"returnParameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":47,"src":"1893:7:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":44,"name":"uint256","nodeType":"ElementaryTypeName","src":"1893:7:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1892:9:1"},"scope":48,"src":"1832:70:1","stateMutability":"view","virtual":false,"visibility":"external"}],"scope":49,"src":"1026:878:1","usedErrors":[],"usedEvents":[31]}],"src":"32:1873:1"},"id":1},"contracts/IUserRegistry.sol":{"ast":{"absolutePath":"contracts/IUserRegistry.sol","exportedSymbols":{"IAddressNaming":[21],"IUserRegistry":[63]},"id":64,"license":"MIT","nodeType":"SourceUnit","nodes":[{"id":50,"literals":["solidity","^","0.8",".0"],"nodeType":"PragmaDirective","src":"32:23:2"},{"absolutePath":"contracts/IAddressNaming.sol","file":"./IAddressNaming.sol","id":51,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":64,"sourceUnit":22,"src":"57:30:2","symbolAliases":[],"unitAlias":""},{"abstract":false,"baseContracts":[{"baseName":{"id":53,"name":"IAddressNaming","nameLocations":["962:14:2"],"nodeType":"IdentifierPath","referencedDeclaration":21,"src":"962:14:2"},"id":54,"nodeType":"InheritanceSpecifier","src":"962:14:2"}],"canonicalName":"IUserRegistry","contractDependencies":[],"contractKind":"interface","documentation":{"id":52,"nodeType":"StructuredDocumentation","src":"89:845:2","text":" @title IUserRegistry\n @notice Canonical interface for \"I am a user registry\" — the kind of\n service that knows which addresses belong to people on this system.\n Carries IAddressNaming as a base because name resolution is a user-registry\n responsibility. Adds a single membership predicate; implementations decide\n what \"registered\" means in their domain:\n - epistery Agent.sol / DomainAgent.sol: addresses listed on any\n whitelist / ACL under this contract.\n - rootz-v6 UniversalTeamRegistryV4: addresses with a credit account,\n authorized factory, or team membership.\n - rootz-v6 IdentityContractV3: addresses authorized as rivets on this\n identity.\n Off-chain code that wants to ask \"does this system know this address?\"\n holds against this interface and gets a uniform answer."},"fullyImplemented":false,"id":63,"linearizedBaseContracts":[63,21],"name":"IUserRegistry","nameLocation":"945:13:2","nodeType":"ContractDefinition","nodes":[{"documentation":{"id":55,"nodeType":"StructuredDocumentation","src":"983:294:2","text":" @notice True if this registry has a record of the address.\n \"Record\" is implementation-defined — membership, identity,\n credit account, rivet registration, etc.\n @param addr The address to check\n @return True if the address is known to this registry"},"functionSelector":"c3c5a547","id":62,"implemented":false,"kind":"function","modifiers":[],"name":"isRegistered","nameLocation":"1291:12:2","nodeType":"FunctionDefinition","parameters":{"id":58,"nodeType":"ParameterList","parameters":[{"constant":false,"id":57,"mutability":"mutable","name":"addr","nameLocation":"1312:4:2","nodeType":"VariableDeclaration","scope":62,"src":"1304:12:2","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56,"name":"address","nodeType":"ElementaryTypeName","src":"1304:7:2","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1303:14:2"},"returnParameters":{"id":61,"nodeType":"ParameterList","parameters":[{"constant":false,"id":60,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":62,"src":"1341:4:2","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":59,"name":"bool","nodeType":"ElementaryTypeName","src":"1341:4:2","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1340:6:2"},"scope":63,"src":"1282:65:2","stateMutability":"view","virtual":false,"visibility":"external"}],"scope":64,"src":"935:414:2","usedErrors":[],"usedEvents":[]}],"src":"32:1318:2"},"id":2}},"contracts":{"contracts/IAddressNaming.sol":{"IAddressNaming":{"abi":[{"inputs":[{"internalType":"address","name":"ownerAddress","type":"address"},{"internalType":"address","name":"addr","type":"address"}],"name":"getAddressName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"name","type":"string"}],"name":"setAddressName","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"methodIdentifiers":{"getAddressName(address,address)":"b715bb74","setAddressName(address,string)":"3037c5ad"}},"metadata":"{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ownerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getAddressName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setAddressName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getAddressName(address,address)\":{\"params\":{\"addr\":\"The address to resolve\",\"ownerAddress\":\"The naming-scope owner; ignored by single-tenant implementations, used by multi-tenant ones\"},\"returns\":{\"_0\":\"The name, or empty string if unset\"}},\"setAddressName(address,string)\":{\"params\":{\"addr\":\"The address to name\",\"name\":\"The name string; empty string clears\"}}},\"title\":\"IAddressNaming\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getAddressName(address,address)\":{\"notice\":\"Resolve an address to its name.\"},\"setAddressName(address,string)\":{\"notice\":\"Set the human-readable name for an address.\"}},\"notice\":\"Canonical interface for resolving identity names from addresses. Names belong to the address itself, not to any (address, list) join. Roles (\\\"owner\\\", \\\"admin\\\", \\\"read\\\", ...) remain on whitelist / ACL entries; names do not. The same address may carry different per-list handles in legacy WhitelistEntry.name fields, but its identity name lives behind this interface. Implementations may be multi-tenant or single-tenant: - Multi-tenant (e.g. epistery Agent.sol): the read accepts an ownerAddress scope; writes are keyed by msg.sender. - Single-tenant (e.g. epistery-host DomainAgent.sol): the read's ownerAddress argument is accepted on the signature for ABI compatibility but ignored; writes are admin-gated. Off-chain consumers (e.g. epistery's Utils.ResolveAddressName, Utils.SetAddressName) hold against this interface, so they work uniformly against either implementation without branching on contract type.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/IAddressNaming.sol\":\"IAddressNaming\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/IAddressNaming.sol\":{\"keccak256\":\"0xf8b93ac3414bd15df108ea437af325845e6c2328a079a7488d034e098326e5eb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7d82ba022d574b496e5e059997eca06b2e6d9dffcc568863b0eefa4b0d5bdd0e\",\"dweb:/ipfs/QmbT4Dg9ky58kew75JHwruwMW61cPhZuF2dARa8StKaELb\"]}},\"version\":1}"}},"contracts/ICreditAccount.sol":{"ICreditAccount":{"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CreditsDeposited","type":"event"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositCredits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserCredits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"methodIdentifiers":{"depositCredits(address,uint256)":"1409f160","getUserCredits(address)":"81b26dda"}},"metadata":"{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CreditsDeposited\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"depositCredits\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"getUserCredits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"CreditsDeposited(address,uint256)\":{\"params\":{\"amount\":\"The credit amount added\",\"user\":\"The user whose balance increased\"}}},\"kind\":\"dev\",\"methods\":{\"depositCredits(address,uint256)\":{\"params\":{\"amount\":\"The credit amount to deposit\",\"user\":\"The account to credit\"}},\"getUserCredits(address)\":{\"params\":{\"user\":\"The account to read\"},\"returns\":{\"_0\":\"The current credit balance\"}}},\"title\":\"ICreditAccount\",\"version\":1},\"userdoc\":{\"events\":{\"CreditsDeposited(address,uint256)\":{\"notice\":\"Emitted when credits are added to an account.\"}},\"kind\":\"user\",\"methods\":{\"depositCredits(address,uint256)\":{\"notice\":\"Deposit credits for `user`, paying with native token. The native token amount is `msg.value`; implementations convert to credit units according to their rate table.\"},\"getUserCredits(address)\":{\"notice\":\"Read the current credit balance for `user`.\"}},\"notice\":\"Canonical interface for credit-bearing user accounts. Signatures match Steven's `UniversalTeamRegistryV4` on Polygon mainnet (`0x83B25fDD25516057AaaAf8027464C8bbb2f91d5B`) so that contract can declare conformance without renaming any existing methods. Implementations decide the conversion between native token (POL/ETH) and credits. UniversalTeamRegistryV4 uses 1 POL = 1,000,000 credits. The user-facing surface is deposit + read. Implementation-private operations (funding specific child contracts like Secrets or KeyVaults, setting rate tables, etc.) are NOT part of this interface \\u2014 they're authorization-gated internals. Epistery does not yet implement credit accounting. This interface is declared on the epistery side as the cross-system spec; epistery contracts may adopt it later, or epistery-host may delegate credit operations to rootz-v6's deployed Registry.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ICreditAccount.sol\":\"ICreditAccount\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/ICreditAccount.sol\":{\"keccak256\":\"0x106c366de017885ff2f9e2ecf3c6822a7972cde95c28f19dab0132ab62b9ef4a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://89157a024cd18708980f20c2eabf0259451a3ff5a92ec067c7d45cca31315e67\",\"dweb:/ipfs/QmcNPfVFXqpnHWq4i9byjFzpZSJ3WJJfQgh7qfB1dp8G82\"]}},\"version\":1}"}},"contracts/IUserRegistry.sol":{"IUserRegistry":{"abi":[{"inputs":[{"internalType":"address","name":"ownerAddress","type":"address"},{"internalType":"address","name":"addr","type":"address"}],"name":"getAddressName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"name","type":"string"}],"name":"setAddressName","outputs":[],"stateMutability":"nonpayable","type":"function"}],"evm":{"bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"methodIdentifiers":{"getAddressName(address,address)":"b715bb74","isRegistered(address)":"c3c5a547","setAddressName(address,string)":"3037c5ad"}},"metadata":"{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ownerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getAddressName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isRegistered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setAddressName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getAddressName(address,address)\":{\"params\":{\"addr\":\"The address to resolve\",\"ownerAddress\":\"The naming-scope owner; ignored by single-tenant implementations, used by multi-tenant ones\"},\"returns\":{\"_0\":\"The name, or empty string if unset\"}},\"isRegistered(address)\":{\"params\":{\"addr\":\"The address to check\"},\"returns\":{\"_0\":\"True if the address is known to this registry\"}},\"setAddressName(address,string)\":{\"params\":{\"addr\":\"The address to name\",\"name\":\"The name string; empty string clears\"}}},\"title\":\"IUserRegistry\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getAddressName(address,address)\":{\"notice\":\"Resolve an address to its name.\"},\"isRegistered(address)\":{\"notice\":\"True if this registry has a record of the address. \\\"Record\\\" is implementation-defined \\u2014 membership, identity, credit account, rivet registration, etc.\"},\"setAddressName(address,string)\":{\"notice\":\"Set the human-readable name for an address.\"}},\"notice\":\"Canonical interface for \\\"I am a user registry\\\" \\u2014 the kind of service that knows which addresses belong to people on this system. Carries IAddressNaming as a base because name resolution is a user-registry responsibility. Adds a single membership predicate; implementations decide what \\\"registered\\\" means in their domain: - epistery Agent.sol / DomainAgent.sol: addresses listed on any whitelist / ACL under this contract. - rootz-v6 UniversalTeamRegistryV4: addresses with a credit account, authorized factory, or team membership. - rootz-v6 IdentityContractV3: addresses authorized as rivets on this identity. Off-chain code that wants to ask \\\"does this system know this address?\\\" holds against this interface and gets a uniform answer.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/IUserRegistry.sol\":\"IUserRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/IAddressNaming.sol\":{\"keccak256\":\"0xf8b93ac3414bd15df108ea437af325845e6c2328a079a7488d034e098326e5eb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7d82ba022d574b496e5e059997eca06b2e6d9dffcc568863b0eefa4b0d5bdd0e\",\"dweb:/ipfs/QmbT4Dg9ky58kew75JHwruwMW61cPhZuF2dARa8StKaELb\"]},\"contracts/IUserRegistry.sol\":{\"keccak256\":\"0x7d56fa638d36ef669871b65c07f8342b8bd09f5a138ddd5cff64e1090d49f806\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://76c9d11f44bc0c2bbccdecd25f8f025ee6a8ae25190f6d88b1ac31251edac1c1\",\"dweb:/ipfs/QmRJvZ1PmJW346FqA48aU8XBR8LhDFBMt6mUDGGPU73pmo\"]}},\"version\":1}"}}}}}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_format": "hh-sol-artifact-1",
|
|
3
|
+
"contractName": "ICreditAccount",
|
|
4
|
+
"sourceName": "contracts/ICreditAccount.sol",
|
|
5
|
+
"abi": [
|
|
6
|
+
{
|
|
7
|
+
"anonymous": false,
|
|
8
|
+
"inputs": [
|
|
9
|
+
{
|
|
10
|
+
"indexed": true,
|
|
11
|
+
"internalType": "address",
|
|
12
|
+
"name": "user",
|
|
13
|
+
"type": "address"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"indexed": false,
|
|
17
|
+
"internalType": "uint256",
|
|
18
|
+
"name": "amount",
|
|
19
|
+
"type": "uint256"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"name": "CreditsDeposited",
|
|
23
|
+
"type": "event"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"inputs": [
|
|
27
|
+
{
|
|
28
|
+
"internalType": "address",
|
|
29
|
+
"name": "user",
|
|
30
|
+
"type": "address"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"internalType": "uint256",
|
|
34
|
+
"name": "amount",
|
|
35
|
+
"type": "uint256"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"name": "depositCredits",
|
|
39
|
+
"outputs": [],
|
|
40
|
+
"stateMutability": "payable",
|
|
41
|
+
"type": "function"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"inputs": [
|
|
45
|
+
{
|
|
46
|
+
"internalType": "address",
|
|
47
|
+
"name": "user",
|
|
48
|
+
"type": "address"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"name": "getUserCredits",
|
|
52
|
+
"outputs": [
|
|
53
|
+
{
|
|
54
|
+
"internalType": "uint256",
|
|
55
|
+
"name": "",
|
|
56
|
+
"type": "uint256"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"stateMutability": "view",
|
|
60
|
+
"type": "function"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"bytecode": "0x",
|
|
64
|
+
"deployedBytecode": "0x",
|
|
65
|
+
"linkReferences": {},
|
|
66
|
+
"deployedLinkReferences": {}
|
|
67
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_format": "hh-sol-artifact-1",
|
|
3
|
+
"contractName": "IUserRegistry",
|
|
4
|
+
"sourceName": "contracts/IUserRegistry.sol",
|
|
5
|
+
"abi": [
|
|
6
|
+
{
|
|
7
|
+
"inputs": [
|
|
8
|
+
{
|
|
9
|
+
"internalType": "address",
|
|
10
|
+
"name": "ownerAddress",
|
|
11
|
+
"type": "address"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"internalType": "address",
|
|
15
|
+
"name": "addr",
|
|
16
|
+
"type": "address"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"name": "getAddressName",
|
|
20
|
+
"outputs": [
|
|
21
|
+
{
|
|
22
|
+
"internalType": "string",
|
|
23
|
+
"name": "",
|
|
24
|
+
"type": "string"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"stateMutability": "view",
|
|
28
|
+
"type": "function"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"inputs": [
|
|
32
|
+
{
|
|
33
|
+
"internalType": "address",
|
|
34
|
+
"name": "addr",
|
|
35
|
+
"type": "address"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"name": "isRegistered",
|
|
39
|
+
"outputs": [
|
|
40
|
+
{
|
|
41
|
+
"internalType": "bool",
|
|
42
|
+
"name": "",
|
|
43
|
+
"type": "bool"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"stateMutability": "view",
|
|
47
|
+
"type": "function"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"inputs": [
|
|
51
|
+
{
|
|
52
|
+
"internalType": "address",
|
|
53
|
+
"name": "addr",
|
|
54
|
+
"type": "address"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"internalType": "string",
|
|
58
|
+
"name": "name",
|
|
59
|
+
"type": "string"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"name": "setAddressName",
|
|
63
|
+
"outputs": [],
|
|
64
|
+
"stateMutability": "nonpayable",
|
|
65
|
+
"type": "function"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"bytecode": "0x",
|
|
69
|
+
"deployedBytecode": "0x",
|
|
70
|
+
"linkReferences": {},
|
|
71
|
+
"deployedLinkReferences": {}
|
|
72
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @title ICreditAccount
|
|
6
|
+
* @notice Canonical interface for credit-bearing user accounts.
|
|
7
|
+
*
|
|
8
|
+
* Signatures match Steven's `UniversalTeamRegistryV4` on Polygon mainnet
|
|
9
|
+
* (`0x83B25fDD25516057AaaAf8027464C8bbb2f91d5B`) so that contract can
|
|
10
|
+
* declare conformance without renaming any existing methods.
|
|
11
|
+
*
|
|
12
|
+
* Implementations decide the conversion between native token (POL/ETH)
|
|
13
|
+
* and credits. UniversalTeamRegistryV4 uses 1 POL = 1,000,000 credits.
|
|
14
|
+
*
|
|
15
|
+
* The user-facing surface is deposit + read. Implementation-private
|
|
16
|
+
* operations (funding specific child contracts like Secrets or KeyVaults,
|
|
17
|
+
* setting rate tables, etc.) are NOT part of this interface — they're
|
|
18
|
+
* authorization-gated internals.
|
|
19
|
+
*
|
|
20
|
+
* Epistery does not yet implement credit accounting. This interface is
|
|
21
|
+
* declared on the epistery side as the cross-system spec; epistery
|
|
22
|
+
* contracts may adopt it later, or epistery-host may delegate credit
|
|
23
|
+
* operations to rootz-v6's deployed Registry.
|
|
24
|
+
*/
|
|
25
|
+
interface ICreditAccount {
|
|
26
|
+
/**
|
|
27
|
+
* @notice Emitted when credits are added to an account.
|
|
28
|
+
* @param user The user whose balance increased
|
|
29
|
+
* @param amount The credit amount added
|
|
30
|
+
*/
|
|
31
|
+
event CreditsDeposited(address indexed user, uint256 amount);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @notice Deposit credits for `user`, paying with native token.
|
|
35
|
+
* The native token amount is `msg.value`; implementations convert
|
|
36
|
+
* to credit units according to their rate table.
|
|
37
|
+
* @param user The account to credit
|
|
38
|
+
* @param amount The credit amount to deposit
|
|
39
|
+
*/
|
|
40
|
+
function depositCredits(address user, uint256 amount) external payable;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @notice Read the current credit balance for `user`.
|
|
44
|
+
* @param user The account to read
|
|
45
|
+
* @return The current credit balance
|
|
46
|
+
*/
|
|
47
|
+
function getUserCredits(address user) external view returns (uint256);
|
|
48
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import "./IAddressNaming.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title IUserRegistry
|
|
8
|
+
* @notice Canonical interface for "I am a user registry" — the kind of
|
|
9
|
+
* service that knows which addresses belong to people on this system.
|
|
10
|
+
*
|
|
11
|
+
* Carries IAddressNaming as a base because name resolution is a user-registry
|
|
12
|
+
* responsibility. Adds a single membership predicate; implementations decide
|
|
13
|
+
* what "registered" means in their domain:
|
|
14
|
+
*
|
|
15
|
+
* - epistery Agent.sol / DomainAgent.sol: addresses listed on any
|
|
16
|
+
* whitelist / ACL under this contract.
|
|
17
|
+
* - rootz-v6 UniversalTeamRegistryV4: addresses with a credit account,
|
|
18
|
+
* authorized factory, or team membership.
|
|
19
|
+
* - rootz-v6 IdentityContractV3: addresses authorized as rivets on this
|
|
20
|
+
* identity.
|
|
21
|
+
*
|
|
22
|
+
* Off-chain code that wants to ask "does this system know this address?"
|
|
23
|
+
* holds against this interface and gets a uniform answer.
|
|
24
|
+
*/
|
|
25
|
+
interface IUserRegistry is IAddressNaming {
|
|
26
|
+
/**
|
|
27
|
+
* @notice True if this registry has a record of the address.
|
|
28
|
+
* "Record" is implementation-defined — membership, identity,
|
|
29
|
+
* credit account, rivet registration, etc.
|
|
30
|
+
* @param addr The address to check
|
|
31
|
+
* @return True if the address is known to this registry
|
|
32
|
+
*/
|
|
33
|
+
function isRegistered(address addr) external view returns (bool);
|
|
34
|
+
}
|
package/docs/IdentityNaming.md
CHANGED
|
@@ -1,57 +1,62 @@
|
|
|
1
1
|
# Identity Naming: Decoupling Names from Roles and Lists
|
|
2
2
|
|
|
3
|
-
**Status:** Introduced in
|
|
3
|
+
**Status:** Introduced 2026-05-13 as the first interface in the cross-system epistery contract spec — `IAddressNaming` (`contracts/IAddressNaming.sol`). The epistery package exports the interface; the deployed contracts in each repo (`epistery-host/contracts/DomainAgent.sol`, `rootz-v6/contracts/UniversalTeamRegistryV4.sol`, …) opt in by declaring `is IAddressNaming` and bumping their own VERSION.
|
|
4
4
|
|
|
5
5
|
## Principle
|
|
6
6
|
|
|
7
|
-
The human-readable name of an address is a property of the **address itself**, not of any (address, list) join. Roles ("owner", "admin", "read",
|
|
7
|
+
The human-readable name of an address is a property of the **address itself**, not of any (address, list) join. Roles ("owner", "admin", "read", …) belong on whitelist entries; names do not.
|
|
8
8
|
|
|
9
9
|
### Why this matters
|
|
10
10
|
|
|
11
|
-
Earlier versions used `WhitelistEntry.name` as the identity-name source.
|
|
11
|
+
Earlier versions used `WhitelistEntry.name` as the identity-name source. Two failure modes:
|
|
12
12
|
|
|
13
13
|
1. The same address on multiple lists could carry different names — the resolver returned whichever it walked first.
|
|
14
14
|
2. Privileged addresses (the contract sponsor / domain host) often surface in portal UIs as `(auto) Owner` or `(auto) Host` rows with role-label strings in the name slot, marked uneditable. Those addresses became "stranded" — the system couldn't recognize them under the user's real name.
|
|
15
15
|
|
|
16
|
-
The fix
|
|
16
|
+
The fix: give names their own primitive, separate from whitelists, exposed through a shared interface so every contract that needs identity naming implements it the same way.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## The interface (`contracts/IAddressNaming.sol`)
|
|
19
19
|
|
|
20
20
|
```solidity
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
interface IAddressNaming {
|
|
22
|
+
function setAddressName(address addr, string memory name) external;
|
|
23
|
+
function getAddressName(address ownerAddress, address addr) external view returns (string memory);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
event AddressNameSet(address indexed owner, address indexed addr, string name);
|
|
27
|
+
Pass an empty string to `setAddressName` to clear a name. Names are limited only by gas / storage cost; epistery clients clamp to 128 chars at the route layer.
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
function setAddressName(address addr, string memory name) external;
|
|
29
|
+
### How implementations differ
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
function getAddressName(address ownerAddress, address addr) external view returns (string memory);
|
|
32
|
-
```
|
|
31
|
+
The interface accommodates two tenancy models:
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
| Implementation | Tenancy | Storage | `ownerAddress` arg on read |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| `epistery/contracts/agent.sol` (archetype) | Multi-tenant | `addressNames[msg.sender][addr] → name` | Used to select the naming scope |
|
|
36
|
+
| `epistery-host/contracts/DomainAgent.sol` | Single-tenant (per domain) | `addressNames[addr] → name` | Accepted on the signature for ABI parity; ignored |
|
|
37
|
+
| `rootz-v6/.../UniversalTeamRegistryV4.sol` | (when adopted) | per Steven's design | per Steven's design |
|
|
38
|
+
|
|
39
|
+
`epistery/contracts/agent.sol` is the **archetype** — a reference implementation, not a deployed contract. The actually-deployed contracts are forks (`DomainAgent.sol`, `UniversalTeamRegistryV4.sol`) that adopt the interface independently.
|
|
35
40
|
|
|
36
41
|
### What did NOT change
|
|
37
42
|
|
|
38
|
-
`WhitelistEntry { addr, name, role, meta }` keeps all four fields. The `name`
|
|
43
|
+
`WhitelistEntry { addr, name, role, meta }` (and the `ACLEntry` equivalent in `DomainAgent.sol`) keeps all four fields. The per-entry `name` slot is now reinterpreted as a **per-list handle / role-label slot** — it may evolve into a useful per-list display field, but it is no longer the identity name source. The resolver does not read it.
|
|
39
44
|
|
|
40
|
-
Existing data in `
|
|
45
|
+
Existing data in those `name` fields is preserved on chain; the only change is that nothing in the auth path consults it for identity.
|
|
41
46
|
|
|
42
|
-
###
|
|
47
|
+
### Contracts that haven't adopted yet
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
For contracts deployed before `is IAddressNaming` was declared on them, the `getAddressName` call reverts. The TypeScript resolver swallows the resulting RPC error and returns `undefined` — the request still goes through, just without a resolved name. Domains running pre-adoption contracts continue to function; they just have no addresses with names until the contract is upgraded.
|
|
45
50
|
|
|
46
51
|
## TypeScript surface
|
|
47
52
|
|
|
48
53
|
### `Utils` static methods (`src/utils/Utils.ts`)
|
|
49
54
|
|
|
50
55
|
```ts
|
|
51
|
-
// Read — one RPC call, returns undefined if unset or on
|
|
56
|
+
// Read — one RPC call, returns undefined if unset or on pre-adoption contracts
|
|
52
57
|
Utils.ResolveAddressName(
|
|
53
58
|
wallet: Wallet,
|
|
54
|
-
ownerAddress: string, // typically domain wallet
|
|
59
|
+
ownerAddress: string, // the naming-scope owner (typically the domain wallet)
|
|
55
60
|
addressToCheck: string,
|
|
56
61
|
contractAddress?: string,
|
|
57
62
|
): Promise<string | undefined>;
|
|
@@ -65,6 +70,8 @@ Utils.SetAddressName(
|
|
|
65
70
|
): Promise<any>;
|
|
66
71
|
```
|
|
67
72
|
|
|
73
|
+
Both work uniformly against any contract that declares `is IAddressNaming`. The off-chain code holds against the interface signature, not against any particular contract type.
|
|
74
|
+
|
|
68
75
|
### `EpisteryAttach` (instance methods on `index.mjs`)
|
|
69
76
|
|
|
70
77
|
```js
|
|
@@ -88,7 +95,7 @@ Mounted under the whitelist router (`routes/whitelist/index.mjs`):
|
|
|
88
95
|
|
|
89
96
|
`setName` validates `address` (0x-prefixed 40 hex), accepts any string for `name` (empty string clears), and clamps name length to 128 chars.
|
|
90
97
|
|
|
91
|
-
`resolveName` reads
|
|
98
|
+
`resolveName` reads from whichever `IAddressNaming` contract this domain is configured with.
|
|
92
99
|
|
|
93
100
|
## Auth middleware
|
|
94
101
|
|
|
@@ -103,30 +110,28 @@ Downstream consumers can read the resolved name from:
|
|
|
103
110
|
|
|
104
111
|
The client-side `ClientWalletInfo` interface (`src/utils/types.ts`) has `name?: string` for type completeness.
|
|
105
112
|
|
|
106
|
-
##
|
|
113
|
+
## Adoption — per fork
|
|
107
114
|
|
|
108
|
-
|
|
115
|
+
The interface ships in the epistery npm package. Each deployed-contract fork adopts on its own cadence:
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
2. **Bootstrap names** after redeploy. For each address that should have a name (you, your collaborators, named services), call:
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
curl -X POST https://<your-domain>/.well-known/epistery/whitelist/setName \
|
|
116
|
-
-H "Cookie: _epistery=<your admin session>" \
|
|
117
|
-
-H "Content-Type: application/json" \
|
|
118
|
-
-d '{"address":"0xe75Fc5...", "name":"michael"}'
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Or programmatically:
|
|
117
|
+
### For `epistery-host/contracts/DomainAgent.sol`
|
|
122
118
|
|
|
119
|
+
1. `import "epistery/contracts/IAddressNaming.sol";` and declare `is IAddressNaming` on the contract (already done as of v1.4.1).
|
|
120
|
+
2. Add `mapping(address => string) private addressNames;` and implement `setAddressName` / `getAddressName` (already done).
|
|
121
|
+
3. Recompile, redeploy, update `~/.epistery/{domain}/config.ini` to point at the new contract address (the deploy flow in `index.mjs` writes this; the migration helper in `utils/DomainChain.mjs` lifts old `WhitelistEntry.name` values into the new mapping).
|
|
122
|
+
4. Bootstrap names admin-side:
|
|
123
123
|
```js
|
|
124
124
|
await epistery.setAddressName("0xe75Fc5...", "michael");
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
### For `rootz-v6/.../UniversalTeamRegistryV4.sol`
|
|
128
|
+
|
|
129
|
+
Steven's call when he wants to. Adoption is:
|
|
130
|
+
1. `import "epistery/contracts/IAddressNaming.sol";` and declare `is IAddressNaming`.
|
|
131
|
+
2. Add the `addressNames` mapping + the two methods. Choose the tenancy model that matches his contract's existing scope (single- or multi-tenant on `msg.sender`).
|
|
132
|
+
3. Redeploy (or use his existing upgrade path).
|
|
128
133
|
|
|
129
|
-
|
|
134
|
+
Off-chain consumers (epistery's `Utils.ResolveAddressName`, anyone using the resolver via the npm package) keep working against either side without code changes.
|
|
130
135
|
|
|
131
136
|
## Related changes in the same release
|
|
132
137
|
|
|
@@ -139,4 +144,6 @@ The motivating bug: a user whose desktop is the contract sponsor was being rende
|
|
|
139
144
|
|
|
140
145
|
The structural cause: `WhitelistEntry.name` was overloading two distinct concepts — a per-list role/handle label, and the user's identity name. The same address on different lists could legitimately have different per-list handles, but the user has *one* name. Putting that name on the join was wrong.
|
|
141
146
|
|
|
142
|
-
The fix is the minimum architectural correction: pull the name off the join, put it on the address, scoped by the domain that's doing the naming. Roles stay where they are. Old data stays where it is. The resolver gets simpler (one RPC call), and privileged-address rendering becomes the portal UI's concern, not the data model's.
|
|
147
|
+
The fix is the minimum architectural correction: pull the name off the join, put it on the address, scoped by the domain that's doing the naming. Roles stay where they are. Old data stays where it is. The resolver gets simpler (one RPC call), and privileged-address rendering becomes the portal UI's concern, not the data model's.
|
|
148
|
+
|
|
149
|
+
The cross-system mechanism is the interface (`IAddressNaming`) — every contract that wants to be a naming source declares conformance. The interface lives in epistery; the implementations live in the forks. No code is shared, no contract inherits from another; alignment is by signature, not by source.
|
package/package.json
CHANGED
|
@@ -563,17 +563,19 @@ export default function whitelistRoutes(epistery) {
|
|
|
563
563
|
});
|
|
564
564
|
|
|
565
565
|
// Resolve address name endpoint — public read of the on-chain mapping.
|
|
566
|
+
// Returns name: null for any unset / unconfigured case (domains without
|
|
567
|
+
// an agent contract, addresses without a name set). Opportunistic — no
|
|
568
|
+
// log noise on the common no-name path.
|
|
566
569
|
router.get("/resolveName", async (req, res) => {
|
|
570
|
+
const address = req.query.address;
|
|
571
|
+
if (!address || !/^0x[a-fA-F0-9]{40}$/.test(address)) {
|
|
572
|
+
return res.status(400).json({ error: "Invalid address parameter" });
|
|
573
|
+
}
|
|
567
574
|
try {
|
|
568
|
-
const address = req.query.address;
|
|
569
|
-
if (!address || !/^0x[a-fA-F0-9]{40}$/.test(address)) {
|
|
570
|
-
return res.status(400).json({ error: "Invalid address parameter" });
|
|
571
|
-
}
|
|
572
575
|
const name = await epistery.resolveName(address);
|
|
573
576
|
res.json({ address, name: name || null });
|
|
574
|
-
} catch
|
|
575
|
-
|
|
576
|
-
res.status(500).json({ error: error.message });
|
|
577
|
+
} catch {
|
|
578
|
+
res.json({ address, name: null });
|
|
577
579
|
}
|
|
578
580
|
});
|
|
579
581
|
|