Contract Source Code:
pragma solidity 0.8.17;
// SPDX-License-Identifier: AGPL-3.0-only
import "interface/IAgency.sol";
import "interface/IERC721Receiver.sol";
library Base64 {
bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/// @notice Encodes some bytes to the base64 representation
function encode(bytes memory data) internal pure returns (string memory) {
uint len = data.length;
if (len == 0) return "";
// multiply by 4/3 rounded up
uint encodedLen = 4 * ((len + 2) / 3);
// Add some extra buffer at the end
bytes memory result = new bytes(encodedLen + 32);
bytes memory table = TABLE;
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let i := 0
} lt(i, len) {
} {
i := add(i, 3)
let input := and(mload(add(data, i)), 0xffffff)
let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF))
out := shl(8, out)
out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF))
out := shl(224, out)
mstore(resultPtr, out)
resultPtr := add(resultPtr, 4)
}
switch mod(len, 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
mstore(result, encodedLen)
}
return string(result);
}
}
contract AgentNFT {
IAgency public immutable agency;
/// @dev ERC165 interface ID of ERC165
bytes4 private constant ERC165_INTERFACE_ID = 0x01ffc9a7;
/// @dev ERC165 interface ID of ERC721
bytes4 private constant ERC721_INTERFACE_ID = 0x80ac58cd;
/// @dev ERC165 interface ID of ERC721Metadata
bytes4 private constant ERC721_METADATA_INTERFACE_ID = 0x5b5e139f;
/// @dev Get the approved address for a single NFT.
mapping(uint => address) public getApproved;
/// @dev Checks if an address is an approved operator.
mapping(address => mapping(address => bool)) public isApprovedForAll;
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
constructor(address _agency) {
agency = IAgency(_agency);
}
/**
* @dev Interface identification is specified in ERC-165.
* @param interfaceID Id of the interface
*/
function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
return (interfaceID == ERC165_INTERFACE_ID ||
interfaceID == ERC721_INTERFACE_ID ||
interfaceID == ERC721_METADATA_INTERFACE_ID);
}
function name() external pure returns (string memory) {
return "Agent";
}
function symbol() external pure returns (string memory) {
return "DAG";
}
function tokenURI(uint tokenId) external view returns (string memory) {
(address owner, uint tier, uint birth, uint parent,) = agency.getAgent(tokenId);
require(owner != address(0), "token not exist");
return _tokenURI(tokenId, parent, tier, birth);
}
function _tokenURI(uint tokenId, uint parent, uint tier, uint birth) internal pure returns (string memory output) {
output = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';
output = string(abi.encodePacked(output, "token ", _toString(tokenId), '</text><text x="10" y="40" class="base">'));
output = string(abi.encodePacked(output, "referer ", _toString(parent), '</text><text x="10" y="60" class="base">'));
output = string(abi.encodePacked(output, "agent_tier ", _toString(tier), '</text><text x="10" y="80" class="base">'));
output = string(abi.encodePacked(output, "time_of_creation ", _toString(birth), '</text></svg>'));
string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Agent #', _toString(tokenId), '", "description": "Dyson Finance Agent NFT", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}'))));
output = string(abi.encodePacked('data:application/json;base64,', json));
}
function _toString(uint value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint temp = value;
uint digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint(value % 10)));
value /= 10;
}
return string(buffer);
}
function totalSupply() external view returns (uint) {
return agency.totalSupply();
}
function balanceOf(address owner) external view returns (uint balance) {
return agency.whois(owner) == 0 ? 0 : 1;
}
function ownerOf(uint tokenId) public view returns (address owner) {
(owner,,,,) = agency.getAgent(tokenId);
}
function onMint(address user, uint tokenId) external {
require(msg.sender == address(agency), "forbidden");
emit Transfer(address(0), user, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint tokenId
) external {
safeTransferFrom(from, to, tokenId, '');
}
function approve(address to, uint tokenId) external {
address owner = ownerOf(tokenId);
// Throws if `tokenId` is not a valid NFT
require(owner != address(0), "token not exist");
// Check requirements
require(owner == msg.sender || isApprovedForAll[owner][msg.sender], "forbidden");
getApproved[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function setApprovalForAll(address operator, bool approved) external {
require(operator != msg.sender, "self approval");
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function _transferFrom(
address from,
address to,
uint tokenId,
address sender
) internal {
require(from == sender || isApprovedForAll[from][sender] || getApproved[tokenId] == sender, "forbidden");
getApproved[tokenId] = address(0);
require(agency.transfer(from, to, tokenId), "forbidden");
emit Transfer(from, to, tokenId);
}
function transferFrom(
address from,
address to,
uint tokenId
) external {
_transferFrom(from, to, tokenId, msg.sender);
}
function _isContract(address account) internal view returns (bool) {
uint size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function safeTransferFrom(
address from,
address to,
uint tokenId,
bytes memory data
) public {
_transferFrom(from, to, tokenId, msg.sender);
if (_isContract(to)) {
try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
require(retval == IERC721Receiver.onERC721Received.selector, "transfer failed");
} catch (bytes memory reason) {
if (reason.length == 0) {
revert('ERC721: transfer to non ERC721Receiver implementer');
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
pragma solidity >=0.8.0;
// SPDX-License-Identifier: MIT
interface IAgency {
struct Agent {
address owner;
uint gen;
uint birth;
uint parentId;
uint[] childrenId;
}
event TransferOwnership(address newOwner);
event Register(uint indexed referrer, uint referee);
event Sign(address indexed signer, bytes32 digest);
function REGISTER_ONCE_TYPEHASH() external view returns (bytes32);
function REGISTER_PARENT_TYPEHASH() external view returns (bytes32);
function MAX_NUM_CHILDREN() external view returns (uint);
function REGISTER_DELAY() external view returns (uint);
function TRANSFER_CD() external view returns (uint);
function agentNFT() external view returns (address);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function whois(address agent) external view returns (uint);
function oneTimeCodes(address once) external view returns (bool);
function presign(address agent, bytes32 digest) external view returns (bool);
function isController(address agent) external view returns (bool);
function owner() external view returns (address);
function userInfo(address agent) external view returns (address ref, uint gen);
function transfer(address from, address to, uint id) external returns (bool);
function totalSupply() external view returns (uint);
function getAgent(uint id) external view returns (address, uint, uint, uint, uint[] memory);
function transferOwnership(address owner) external;
function addController(address _controller) external;
function removeController(address _controller) external;
function rescueERC20(address tokenAddress, address to, uint256 amount) external;
function adminAdd(address newUser) external returns (uint id);
function register(bytes memory parentSig, bytes memory onceSig, uint deadline) payable external returns (uint id);
function sign(bytes32 digest) external;
function getHashTypedData(bytes32 structHash) external view returns (bytes32);
function transferCooldown(uint id) external view returns (uint);
}
pragma solidity >=0.8.0;
// SPDX-License-Identifier: MIT
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
function onERC721Received(address, address, uint, bytes calldata) external returns (bytes4);
}