1616
1717pragma solidity ^ 0.8.24 ;
1818
19+ import { ERC721 } from "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol " ;
20+
1921interface GemLike {
2022 function transferFrom (address from , address to , uint256 amount ) external ;
2123 function transfer (address to , uint256 amount ) external ;
@@ -25,19 +27,10 @@ interface IdentityNetworkLike {
2527 function isMember (address account ) external view returns (bool );
2628}
2729
28- interface ERC721ReceiverLike {
29- function onERC721Received (
30- address operator ,
31- address from ,
32- uint256 tokenId ,
33- bytes calldata data
34- ) external returns (bytes4 );
35- }
36-
3730/// @title NFATFacility
3831/// @notice Non-Fungible Allocation Token Facility for bespoke capital deployment deals
3932/// @dev Implements queue-based deposits and ERC-721 NFAT minting
40- contract NFATFacility {
33+ contract NFATFacility is ERC721 {
4134
4235 // --- Immutables ---
4336
@@ -62,13 +55,7 @@ contract NFATFacility {
6255
6356 // --- NFAT Storage ---
6457
65- string public name;
66- string public symbol;
6758 uint256 public nextTokenId;
68- mapping (uint256 tokenId = > address owner ) internal _owners;
69- mapping (address owner = > uint256 count ) internal _balances;
70- mapping (uint256 tokenId = > address approved ) internal _tokenApprovals;
71- mapping (address owner = > mapping (address operator = > bool approved )) internal _operatorApprovals;
7259
7360 // --- Events: Access Control ---
7461
@@ -93,12 +80,6 @@ contract NFATFacility {
9380 event Fund (uint256 indexed tokenId , address indexed funder , uint256 amount );
9481 event Redeem (uint256 indexed tokenId , uint256 amount );
9582
96- // --- Events: ERC-721 ---
97-
98- event Transfer (address indexed from , address indexed to , uint256 indexed tokenId );
99- event Approval (address indexed owner , address indexed approved , uint256 indexed tokenId );
100- event ApprovalForAll (address indexed owner , address indexed operator , bool approved );
101-
10283 // --- Modifiers ---
10384
10485 modifier auth () {
@@ -123,11 +104,11 @@ contract NFATFacility {
123104
124105 // --- Constructor ---
125106
126- constructor (address gem_ , address almProxy_ , string memory name_ , string memory symbol_ ) {
107+ constructor (address gem_ , address almProxy_ , string memory name_ , string memory symbol_ )
108+ ERC721 (name_, symbol_)
109+ {
127110 gem = GemLike (gem_);
128111 almProxy = almProxy_;
129- name = name_;
130- symbol = symbol_;
131112 wards[msg .sender ] = 1 ;
132113 emit Rely (msg .sender );
133114 }
@@ -218,22 +199,18 @@ contract NFATFacility {
218199 require (amount > 0 , "NFATFacility/zero-amount " );
219200 require (deposits[target] >= amount, "NFATFacility/insufficient-deposits " );
220201
221- require (identityNetwork == address (0 ) || IdentityNetworkLike (identityNetwork).isMember (target), "NFATFacility/target-not-member " );
222-
223202 uint256 tokenId = nextTokenId++ ;
224203
225204 // Effects - Queue
226205 unchecked { deposits[target] -= amount; }
227206
228- // Effects - NFAT
229- _owners[tokenId] = target;
230- _balances[target] += 1 ;
207+ // Effects - NFAT (identity network check in _update)
208+ _mint (target, tokenId);
231209
232210 // Interactions
233211 gem.transfer (almProxy, amount);
234212
235213 emit Claim (target, tokenId, amount);
236- emit Transfer (address (0 ), target, tokenId);
237214 }
238215
239216 // --- Redeem Functions ---
@@ -242,7 +219,7 @@ contract NFATFacility {
242219 /// @param tokenId The NFAT to fund
243220 /// @param amount The amount of gem to deposit
244221 function fund (uint256 tokenId , uint256 amount ) external {
245- require (_owners[ tokenId] != address (0 ), "NFATFacility/invalid-token " );
222+ require (_ownerOf ( tokenId) != address (0 ), "NFATFacility/invalid-token " );
246223 require (amount > 0 , "NFATFacility/zero-amount " );
247224
248225 // Effects
@@ -261,7 +238,7 @@ contract NFATFacility {
261238 require (amount > 0 , "NFATFacility/zero-amount " );
262239 require (funded[tokenId] >= amount, "NFATFacility/insufficient-funded " );
263240
264- address owner = _owners[ tokenId] ;
241+ address owner = _ownerOf ( tokenId) ;
265242 require (msg .sender == owner, "NFATFacility/not-owner " );
266243
267244 // Effects
@@ -273,89 +250,15 @@ contract NFATFacility {
273250 emit Redeem (tokenId, amount);
274251 }
275252
276- // --- ERC-721 Functions ---
277-
278- function ownerOf (uint256 tokenId ) public view returns (address ) {
279- address owner = _owners[tokenId];
280- require (owner != address (0 ), "NFATFacility/invalid-token " );
281- return owner;
282- }
283-
284- function balanceOf (address owner ) external view returns (uint256 ) {
285- require (owner != address (0 ), "NFATFacility/zero-address " );
286- return _balances[owner];
287- }
288-
289- function approve (address to , uint256 tokenId ) external {
290- address owner = ownerOf (tokenId);
291- require (msg .sender == owner || _operatorApprovals[owner][msg .sender ], "NFATFacility/not-authorized " );
292- _tokenApprovals[tokenId] = to;
293- emit Approval (owner, to, tokenId);
294- }
295-
296- function getApproved (uint256 tokenId ) external view returns (address ) {
297- require (_owners[tokenId] != address (0 ), "NFATFacility/invalid-token " );
298- return _tokenApprovals[tokenId];
299- }
300-
301- function setApprovalForAll (address operator , bool approved ) external {
302- require (operator != msg .sender , "NFATFacility/self-approval " );
303- _operatorApprovals[msg .sender ][operator] = approved;
304- emit ApprovalForAll (msg .sender , operator, approved);
305- }
306-
307- function isApprovedForAll (address owner , address operator ) external view returns (bool ) {
308- return _operatorApprovals[owner][operator];
309- }
310-
311- function transferFrom (address from , address to , uint256 tokenId ) public {
312- require (_isApprovedOrOwner (msg .sender , tokenId), "NFATFacility/not-authorized " );
313- require (ownerOf (tokenId) == from, "NFATFacility/wrong-from " );
314- require (to != address (0 ), "NFATFacility/zero-address " );
315-
316- require (identityNetwork == address (0 ) || IdentityNetworkLike (identityNetwork).isMember (to), "NFATFacility/to-not-member " );
317-
318- // Clear approval
319- _tokenApprovals[tokenId] = address (0 );
320-
321- // Effects
322- _balances[from] -= 1 ;
323- _balances[to] += 1 ;
324- _owners[tokenId] = to;
325-
326- emit Transfer (from, to, tokenId);
327- }
328-
329- function safeTransferFrom (address from , address to , uint256 tokenId ) external {
330- safeTransferFrom (from, to, tokenId, "" );
331- }
332-
333- function safeTransferFrom (address from , address to , uint256 tokenId , bytes memory data ) public {
334- transferFrom (from, to, tokenId);
335- require (_checkOnERC721Received (from, to, tokenId, data), "NFATFacility/unsafe-recipient " );
336- }
337-
338- function _isApprovedOrOwner (address spender , uint256 tokenId ) internal view returns (bool ) {
339- address owner = ownerOf (tokenId);
340- return (spender == owner || _tokenApprovals[tokenId] == spender || _operatorApprovals[owner][spender]);
341- }
342-
343- function _checkOnERC721Received (address from , address to , uint256 tokenId , bytes memory data ) internal returns (bool ) {
344- if (to.code.length == 0 ) {
345- return true ;
346- }
347- try ERC721ReceiverLike (to).onERC721Received (msg .sender , from, tokenId, data) returns (bytes4 retval ) {
348- return retval == ERC721ReceiverLike .onERC721Received.selector ;
349- } catch {
350- return false ;
351- }
352- }
353-
354- // --- ERC-165 ---
253+ // --- ERC-721 Overrides ---
355254
356- function supportsInterface (bytes4 interfaceId ) external pure returns (bool ) {
357- return
358- interfaceId == 0x01ffc9a7 || // ERC-165
359- interfaceId == 0x80ac58cd ; // ERC-721
255+ /// @dev OZ's _mint and transferFrom both revert before calling _update when to == address(0),
256+ /// and _burn is never invoked, so `to` is guaranteed to be non-zero here.
257+ function _update (address to , uint256 tokenId , address auth_ ) internal override returns (address ) {
258+ require (
259+ identityNetwork == address (0 ) || IdentityNetworkLike (identityNetwork).isMember (to),
260+ "NFATFacility/not-member "
261+ );
262+ return super ._update (to, tokenId, auth_);
360263 }
361264}
0 commit comments