📄 AddressRegistry.sol
D-OPEN SOVEREIGN
Documentation & Insights
@title Address Registry
@dev An immutable registry that stores the historical and active deployment addresses for
Ꭰ-Library Core Contracts (Factory, BouncerStorage, BackupStorage, etc.).
Designed to replace build-time static configuration.@dev Transfers administration of the registry to a new address.@dev Appends a new deployed address to the history of a given contract name.
The last appended address is considered the "active" or "latest" version.@dev Appends a new string value to the history of a given data key.
The last appended value is considered the "active" or "latest" version.@dev Returns the most recently deployed (active) address for a given contract name.
Reverts if the contract name has no history.@dev Returns the most recently added value for a given data key.
Reverts if the data key has no history.@dev Returns the entire chronological history of records for a given contract name.
The last record in the array is the current active version.@dev Returns the entire chronological history of strings for a given data key.@dev Returns all recognized contract names currently tracked in the registry.@dev Returns all recognized data keys currently tracked in the registry.@dev Anchors a corpus pointer blob on-chain by storing its Arweave TxID and SHA-256 hash.
The blob is the per-environment corpus sub-block uploaded to Arweave by seed-registry-v2.js.
Key convention: "CORPUS_V2_PROD" (on chain 1116) / "CORPUS_V2_STAGING" (on chain 1114).@dev Returns the most recently anchored blob ref for a given key.@dev Returns a paginated slice of the blob ref history for a given key.
Use offset=0, limit=1 to get the oldest; getLatestBlobRef for the newest.
Historical audit should use indexed BlobRefAdded events instead of this function.@dev Returns all blob ref keys currently tracked in the registry.1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15
16// SPDX-License-Identifier: Apache-2.0
17pragma solidity ^0.8.24;
18
19/**
20 * @title Address Registry
21 * @dev An immutable registry that stores the historical and active deployment addresses for
22 * Ꭰ-Library Core Contracts (Factory, BouncerStorage, BackupStorage, etc.).
23 * Designed to replace build-time static configuration.
24 */
25contract AddressRegistry {
26 address public admin;
27
28 struct ContractRecord {
29 address contractAddress;
30 string abiUrl;
31 }
32
33 // Mapping from Contract Name (e.g., "Factory") to a historical array of deployed records
34 mapping(string => ContractRecord[]) private _contractHistory;
35
36 // Array to keep track of all registered contract names for easy enumeration
37 string[] private _contractNames;
38 // Mapping to prevent duplicates in _contractNames
39 mapping(string => bool) private _nameExists;
40
41 // Mapping from a data key (e.g., "EN_TOPICS") to a historical array of string values
42 mapping(string => string[]) private _dataHistory;
43
44 // Array to keep track of all registered data keys
45 string[] private _dataKeys;
46 // Mapping to prevent duplicates in _dataKeys
47 mapping(string => bool) private _dataKeyExists;
48
49 // Blob references: key → (Arweave TxID, SHA-256 hash) pairs
50 // Used to anchor corpus pointer blobs (e.g., CORPUS_V2_PROD) on-chain for verifiability.
51 struct BlobRef {
52 string arweaveTxId;
53 bytes32 sha256Hash;
54 }
55
56 mapping(string => BlobRef[]) private _blobRefs;
57 string[] private _blobRefKeys;
58 mapping(string => bool) private _blobRefKeyExists;
59
60 event ContractAdded(
61 string indexed name,
62 address indexed contractAddress,
63 string abiUrl,
64 uint256 version
65 );
66
67 event DataAdded(
68 string indexed key,
69 string value,
70 uint256 version
71 );
72
73 event BlobRefAdded(
74 string indexed key,
75 string arweaveTxId,
76 bytes32 sha256Hash,
77 uint256 version
78 );
79
80 event AdminChanged(address indexed oldAdmin, address indexed newAdmin);
81
82 modifier onlyAdmin() {
83 require(
84 msg.sender == admin,
85 "AddressRegistry: caller is not the admin"
86 );
87 _;
88 }
89
90 constructor() {
91 admin = msg.sender;
92 }
93
94 /**
95 * @dev Transfers administration of the registry to a new address.
96 */
97 function changeAdmin(address newAdmin) external onlyAdmin {
98 require(
99 newAdmin != address(0),
100 "AddressRegistry: new admin is the zero address"
101 );
102 emit AdminChanged(admin, newAdmin);
103 admin = newAdmin;
104 }
105
106 /**
107 * @dev Appends a new deployed address to the history of a given contract name.
108 * The last appended address is considered the "active" or "latest" version.
109 */
110 function addContract(
111 string memory name,
112 address contractAddress,
113 string memory abiUrl
114 ) external onlyAdmin {
115 require(
116 contractAddress != address(0),
117 "AddressRegistry: contract address cannot be zero"
118 );
119 require(
120 bytes(name).length > 0,
121 "AddressRegistry: contract name cannot be empty"
122 );
123
124 if (!_nameExists[name]) {
125 _nameExists[name] = true;
126 _contractNames.push(name);
127 }
128
129 _contractHistory[name].push(
130 ContractRecord({contractAddress: contractAddress, abiUrl: abiUrl})
131 );
132
133 uint256 versionIndex = _contractHistory[name].length; // 1-indexed version
134 emit ContractAdded(name, contractAddress, abiUrl, versionIndex);
135 }
136
137 /**
138 * @dev Appends a new string value to the history of a given data key.
139 * The last appended value is considered the "active" or "latest" version.
140 */
141 function addData(
142 string memory key,
143 string memory value
144 ) external onlyAdmin {
145 require(
146 bytes(key).length > 0,
147 "AddressRegistry: data key cannot be empty"
148 );
149 require(
150 bytes(value).length > 0,
151 "AddressRegistry: data value cannot be empty"
152 );
153
154 if (!_dataKeyExists[key]) {
155 _dataKeyExists[key] = true;
156 _dataKeys.push(key);
157 }
158
159 _dataHistory[key].push(value);
160
161 uint256 versionIndex = _dataHistory[key].length; // 1-indexed version
162 emit DataAdded(key, value, versionIndex);
163 }
164
165 /**
166 * @dev Returns the most recently deployed (active) address for a given contract name.
167 * Reverts if the contract name has no history.
168 */
169 function getLatestContract(
170 string memory name
171 ) external view returns (address, string memory) {
172 require(
173 _contractHistory[name].length > 0,
174 "AddressRegistry: contract not found"
175 );
176 ContractRecord memory record = _contractHistory[name][
177 _contractHistory[name].length - 1
178 ];
179 return (record.contractAddress, record.abiUrl);
180 }
181
182 /**
183 * @dev Returns the most recently added value for a given data key.
184 * Reverts if the data key has no history.
185 */
186 function getLatestData(
187 string memory key
188 ) external view returns (string memory) {
189 require(
190 _dataHistory[key].length > 0,
191 "AddressRegistry: data not found"
192 );
193 return _dataHistory[key][_dataHistory[key].length - 1];
194 }
195
196 /**
197 * @dev Returns the entire chronological history of records for a given contract name.
198 * The last record in the array is the current active version.
199 */
200 function getContractHistory(
201 string memory name
202 ) external view returns (ContractRecord[] memory) {
203 return _contractHistory[name];
204 }
205
206 /**
207 * @dev Returns the entire chronological history of strings for a given data key.
208 */
209 function getDataHistory(
210 string memory key
211 ) external view returns (string[] memory) {
212 return _dataHistory[key];
213 }
214
215 /**
216 * @dev Returns all recognized contract names currently tracked in the registry.
217 */
218 function getAllContractNames() external view returns (string[] memory) {
219 return _contractNames;
220 }
221
222 /**
223 * @dev Returns all recognized data keys currently tracked in the registry.
224 */
225 function getAllDataKeys() external view returns (string[] memory) {
226 return _dataKeys;
227 }
228
229 /**
230 * @dev Anchors a corpus pointer blob on-chain by storing its Arweave TxID and SHA-256 hash.
231 * The blob is the per-environment corpus sub-block uploaded to Arweave by seed-registry-v2.js.
232 * Key convention: "CORPUS_V2_PROD" (on chain 1116) / "CORPUS_V2_STAGING" (on chain 1114).
233 */
234 function addBlobRef(
235 string memory key,
236 string memory arweaveTxId,
237 bytes32 sha256Hash
238 ) external onlyAdmin {
239 require(bytes(key).length > 0, "AddressRegistry: key cannot be empty");
240 require(bytes(arweaveTxId).length > 0, "AddressRegistry: txId cannot be empty");
241 require(sha256Hash != bytes32(0), "AddressRegistry: hash cannot be zero");
242
243 if (!_blobRefKeyExists[key]) {
244 _blobRefKeyExists[key] = true;
245 _blobRefKeys.push(key);
246 }
247
248 _blobRefs[key].push(BlobRef({ arweaveTxId: arweaveTxId, sha256Hash: sha256Hash }));
249 uint256 version = _blobRefs[key].length;
250 emit BlobRefAdded(key, arweaveTxId, sha256Hash, version);
251 }
252
253 /**
254 * @dev Returns the most recently anchored blob ref for a given key.
255 */
256 function getLatestBlobRef(
257 string memory key
258 ) external view returns (string memory, bytes32) {
259 require(_blobRefs[key].length > 0, "AddressRegistry: blob ref not found");
260 BlobRef memory ref = _blobRefs[key][_blobRefs[key].length - 1];
261 return (ref.arweaveTxId, ref.sha256Hash);
262 }
263
264 /**
265 * @dev Returns a paginated slice of the blob ref history for a given key.
266 * Use offset=0, limit=1 to get the oldest; getLatestBlobRef for the newest.
267 * Historical audit should use indexed BlobRefAdded events instead of this function.
268 */
269 function getBlobRefHistory(
270 string memory key,
271 uint256 offset,
272 uint256 limit
273 ) external view returns (BlobRef[] memory) {
274 BlobRef[] storage history = _blobRefs[key];
275 uint256 end = offset + limit > history.length ? history.length : offset + limit;
276 if (offset >= end) return new BlobRef[](0);
277 BlobRef[] memory page = new BlobRef[](end - offset);
278 for (uint256 i = offset; i < end; i++) {
279 page[i - offset] = history[i];
280 }
281 return page;
282 }
283
284 /**
285 * @dev Returns all blob ref keys currently tracked in the registry.
286 */
287 function getAllBlobRefKeys() external view returns (string[] memory) {
288 return _blobRefKeys;
289 }
290}
291