Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Attributes to URI #410

Merged
merged 7 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ $ forge build
$ forge test
```

Run tests with `forge test -vvv` to see the console logs, which will show trove URI data.

### Format

```shell
Expand Down
27 changes: 26 additions & 1 deletion contracts/src/NFTMetadata/MetadataNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import "./utils/baseSVG.sol";
import "./utils/bauhaus.sol";

import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol";

import {ITroveManager} from "src/Interfaces/ITroveManager.sol";

interface IMetadataNFT {
struct TroveData {
uint256 _tokenId;
address _owner;
address _collToken;
address _boldToken;
uint256 _collAmount;
uint256 _debtAmount;
uint256 _interestRate;
Expand All @@ -35,7 +38,8 @@ contract MetadataNFT is IMetadataNFT {
}

function uri(TroveData memory _troveData) public view returns (string memory) {
return json.formattedMetadata(name, description, renderSVGImage(_troveData));
string memory attr = attributes(_troveData);
return json.formattedMetadata(name, description, renderSVGImage(_troveData), attr);
}

function renderSVGImage(TroveData memory _troveData) internal view returns (string memory) {
Expand All @@ -45,6 +49,27 @@ contract MetadataNFT is IMetadataNFT {
);
}

function attributes(TroveData memory _troveData) public view returns (string memory) {
//include: collateral token address, collateral amount, debt token address, debt amount, interest rate, status
return string.concat(
'[{"trait_type": "Collateral Token", "value": "',
Strings.toHexString(_troveData._collToken),
'"}, {"trait_type": "Collateral Amount", "value": "',
Strings.toString(_troveData._collAmount),
'"}, {"trait_type": "Debt Token", "value": "',
Strings.toHexString(_troveData._boldToken),
'"}, {"trait_type": "Debt Amount", "value": "',
Strings.toString(_troveData._debtAmount),
'"}, {"trait_type": "Interest Rate", "value": "',
Strings.toString(_troveData._interestRate),
'"}, {"trait_type": "Status", "value": "',
_status2Str(_troveData._status),
'"} ]'
);


}

function dynamicTextComponents(TroveData memory _troveData) public view returns (string memory) {
string memory id = LibString.toHexString(_troveData._tokenId);
id = string.concat(LibString.slice(id, 0, 6), "...", LibString.slice(id, 38, 42));
Expand Down
9 changes: 7 additions & 2 deletions contracts/src/NFTMetadata/utils/JSON.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ library json {

string constant DOUBLE_QUOTES = '\\"';

function formattedMetadata(string memory name, string memory description, string memory svgImg)
function formattedMetadata(string memory name, string memory description, string memory svgImg, string memory attributes)
internal
pure
returns (string memory)
Expand All @@ -19,7 +19,12 @@ library json {
"data:application/json;base64,",
encode(
bytes(
string.concat("{", _prop("name", name), _prop("description", description), _xmlImage(svgImg), "}")
string.concat("{", _prop("name", name),
_prop("description", description),
_xmlImage(svgImg),
',"attributes":',
attributes,
"}")
)
)
);
Expand Down
3 changes: 3 additions & 0 deletions contracts/src/TroveNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {ITroveManager} from "./Interfaces/ITroveManager.sol";
contract TroveNFT is ERC721, ITroveNFT {
ITroveManager public immutable troveManager;
IERC20Metadata internal immutable collToken;
IBoldToken internal immutable boldToken;

IMetadataNFT public immutable metadataNFT;

Expand All @@ -28,6 +29,7 @@ contract TroveNFT is ERC721, ITroveNFT {
troveManager = _addressesRegistry.troveManager();
collToken = _addressesRegistry.collToken();
metadataNFT = _addressesRegistry.metadataNFT();
boldToken = _addressesRegistry.boldToken();
}

function tokenURI(uint256 _tokenId) public view override(ERC721, IERC721Metadata) returns (string memory) {
Expand All @@ -38,6 +40,7 @@ contract TroveNFT is ERC721, ITroveNFT {
_tokenId: _tokenId,
_owner: ownerOf(_tokenId),
_collToken: address(collToken),
_boldToken: address(boldToken),
_collAmount: coll,
_debtAmount: debt,
_interestRate: annualInterestRate,
Expand Down
28 changes: 28 additions & 0 deletions contracts/src/test/troveNFT.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,32 @@ contract troveNFTTest is DevTestSetup {

emit log_string(uri);
}

function testTroveURIAttributes() public {
uint256 troveId = _openTrove();

TroveNFT troveNFT = TroveNFT(address(troveManager.troveNFT()));

string memory uri = troveNFT.tokenURI(troveId);

emit log_string(uri);

/** TODO: validate each individual attribute, or manually make a json and validate it all at once
// Check for expected attributes
assertTrue(LibString.contains(uri, '"trait_type": "Collateral Token"'), "Collateral Token attribute missing");
assertTrue(LibString.contains(uri, '"trait_type": "Collateral Amount"'), "Collateral Amount attribute missing");
assertTrue(LibString.contains(uri, '"trait_type": "Debt Token"'), "Debt Token attribute missing");
assertTrue(LibString.contains(uri, '"trait_type": "Debt Amount"'), "Debt Amount attribute missing");
assertTrue(LibString.contains(uri, '"trait_type": "Interest Rate"'), "Interest Rate attribute missing");
assertTrue(LibString.contains(uri, '"trait_type": "Status"'), "Status attribute missing");

// Check for expected values
//assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(collateral)))), "Incorrect Collateral Token value");
assertTrue(LibString.contains(uri, '"value": "2000000000000000000"'), "Incorrect Collateral Amount value");
assertTrue(LibString.contains(uri, string.concat('"value": "', Strings.toHexString(address(boldToken)))), "Incorrect Debt Token value");
assertTrue(LibString.contains(uri, '"value": "1000000000000000000000"'), "Incorrect Debt Amount value");
assertTrue(LibString.contains(uri, '"value": "5000000000000000"'), "Incorrect Interest Rate value");
assertTrue(LibString.contains(uri, '"value": "Active"'), "Incorrect Status value");
*/
}
}
Loading