Merge branch 'develop' into feature/sc-838/ui-finish-indexed-nfa-view-after-design-changes
This commit is contained in:
commit
7475a62548
|
|
@ -39,6 +39,7 @@ contract FleekERC721 is
|
||||||
string ENS,
|
string ENS,
|
||||||
string commitHash,
|
string commitHash,
|
||||||
string gitRepository,
|
string gitRepository,
|
||||||
|
string ipfsHash,
|
||||||
string logo,
|
string logo,
|
||||||
uint24 color,
|
uint24 color,
|
||||||
bool accessPointAutoApproval,
|
bool accessPointAutoApproval,
|
||||||
|
|
@ -108,6 +109,7 @@ contract FleekERC721 is
|
||||||
string calldata ens,
|
string calldata ens,
|
||||||
string memory commitHash,
|
string memory commitHash,
|
||||||
string memory gitRepository,
|
string memory gitRepository,
|
||||||
|
string memory ipfsHash,
|
||||||
string memory logo,
|
string memory logo,
|
||||||
uint24 color,
|
uint24 color,
|
||||||
bool accessPointAutoApproval,
|
bool accessPointAutoApproval,
|
||||||
|
|
@ -131,7 +133,7 @@ contract FleekERC721 is
|
||||||
|
|
||||||
// The mint interaction is considered to be the first build of the site. Updates from now on all increment the currentBuild by one and update the mapping.
|
// The mint interaction is considered to be the first build of the site. Updates from now on all increment the currentBuild by one and update the mapping.
|
||||||
app.currentBuild = 0;
|
app.currentBuild = 0;
|
||||||
app.builds[0] = Build(commitHash, gitRepository);
|
app.builds[0] = Build(commitHash, gitRepository, ipfsHash, externalURL);
|
||||||
|
|
||||||
emit NewMint(
|
emit NewMint(
|
||||||
tokenId,
|
tokenId,
|
||||||
|
|
@ -141,6 +143,7 @@ contract FleekERC721 is
|
||||||
ens,
|
ens,
|
||||||
commitHash,
|
commitHash,
|
||||||
gitRepository,
|
gitRepository,
|
||||||
|
ipfsHash,
|
||||||
logo,
|
logo,
|
||||||
color,
|
color,
|
||||||
accessPointAutoApproval,
|
accessPointAutoApproval,
|
||||||
|
|
@ -396,11 +399,14 @@ contract FleekERC721 is
|
||||||
function setTokenBuild(
|
function setTokenBuild(
|
||||||
uint256 tokenId,
|
uint256 tokenId,
|
||||||
string memory _commitHash,
|
string memory _commitHash,
|
||||||
string memory _gitRepository
|
string memory _gitRepository,
|
||||||
|
string memory _ipfsHash,
|
||||||
|
string memory _domain
|
||||||
) public virtual requireTokenRole(tokenId, TokenRoles.Controller) {
|
) public virtual requireTokenRole(tokenId, TokenRoles.Controller) {
|
||||||
_requireMinted(tokenId);
|
_requireMinted(tokenId);
|
||||||
_apps[tokenId].builds[++_apps[tokenId].currentBuild] = Build(_commitHash, _gitRepository);
|
_apps[tokenId].builds[++_apps[tokenId].currentBuild] = Build(_commitHash, _gitRepository, _ipfsHash, _domain);
|
||||||
emit MetadataUpdate(tokenId, "build", [_commitHash, _gitRepository], msg.sender);
|
// Note from Nima: should we update the externalURL field with each new domain?
|
||||||
|
emit MetadataUpdate(tokenId, "build", [_commitHash, _gitRepository, _ipfsHash, _domain], msg.sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ interface IERCX {
|
||||||
*/
|
*/
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, string[2] value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, string[4] value, address indexed triggeredBy);
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, bool value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, bool value, address indexed triggeredBy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,6 +33,8 @@ interface IERCX {
|
||||||
struct Build {
|
struct Build {
|
||||||
string commitHash;
|
string commitHash;
|
||||||
string gitRepository;
|
string gitRepository;
|
||||||
|
string ipfsHash;
|
||||||
|
string domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -84,7 +86,13 @@ interface IERCX {
|
||||||
/**
|
/**
|
||||||
* @dev Sets a minted token's build.
|
* @dev Sets a minted token's build.
|
||||||
*/
|
*/
|
||||||
function setTokenBuild(uint256 tokenId, string memory commitHash, string memory gitRepository) external;
|
function setTokenBuild(
|
||||||
|
uint256 tokenId,
|
||||||
|
string memory commitHash,
|
||||||
|
string memory gitRepository,
|
||||||
|
string memory ipfsHash,
|
||||||
|
string memory domain
|
||||||
|
) external;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns the token metadata for a given tokenId.
|
* @dev Returns the token metadata for a given tokenId.
|
||||||
|
|
|
||||||
|
|
@ -369,29 +369,31 @@ contract Test_FleekERC721_AccessControl is Test_FleekERC721_Base, Test_FleekERC7
|
||||||
function test_setTokenBuild() public {
|
function test_setTokenBuild() public {
|
||||||
string memory commitHash = "commitHash";
|
string memory commitHash = "commitHash";
|
||||||
string memory gitRepository = "gitRepository";
|
string memory gitRepository = "gitRepository";
|
||||||
|
string memory ipfsHash = "ipfsHash";
|
||||||
|
string memory domain = "domain";
|
||||||
|
|
||||||
// ColletionOwner
|
// ColletionOwner
|
||||||
vm.prank(collectionOwner);
|
vm.prank(collectionOwner);
|
||||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||||
|
|
||||||
// CollectionVerifier
|
// CollectionVerifier
|
||||||
vm.prank(collectionVerifier);
|
vm.prank(collectionVerifier);
|
||||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||||
|
|
||||||
// TokenOwner
|
// TokenOwner
|
||||||
vm.prank(tokenOwner);
|
vm.prank(tokenOwner);
|
||||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||||
|
|
||||||
// TokenController
|
// TokenController
|
||||||
vm.prank(tokenController);
|
vm.prank(tokenController);
|
||||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||||
|
|
||||||
// AnyAddress
|
// AnyAddress
|
||||||
vm.prank(anyAddress);
|
vm.prank(anyAddress);
|
||||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_burn() public {
|
function test_burn() public {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ contract Test_FleekERC721_Billing is Test_FleekERC721_Base, Test_FleekERC721_Bil
|
||||||
TestConstants.APP_ENS,
|
TestConstants.APP_ENS,
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
||||||
|
|
@ -75,6 +76,7 @@ contract Test_FleekERC721_Billing is Test_FleekERC721_Base, Test_FleekERC721_Bil
|
||||||
TestConstants.APP_ENS,
|
TestConstants.APP_ENS,
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
||||||
|
|
@ -98,6 +100,7 @@ contract Test_FleekERC721_Billing is Test_FleekERC721_Base, Test_FleekERC721_Bil
|
||||||
TestConstants.APP_ENS,
|
TestConstants.APP_ENS,
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ library TestConstants {
|
||||||
|
|
||||||
string public constant APP_GIT_REPOSITORY = "https://github.com/fleekxyz/non-fungible-apps";
|
string public constant APP_GIT_REPOSITORY = "https://github.com/fleekxyz/non-fungible-apps";
|
||||||
|
|
||||||
|
string public constant APP_IPFS_HASH = "mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a";
|
||||||
|
|
||||||
uint24 public constant APP_COLOR = 0x123456;
|
uint24 public constant APP_COLOR = 0x123456;
|
||||||
|
|
||||||
bool public constant APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS = true;
|
bool public constant APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS = true;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ contract Test_FleekERC721_GetToken is Test_FleekERC721_Base {
|
||||||
string memory newENS,
|
string memory newENS,
|
||||||
string memory newCommitHash,
|
string memory newCommitHash,
|
||||||
string memory newRepository,
|
string memory newRepository,
|
||||||
|
string memory newIpfsHash,
|
||||||
|
string memory newDomain,
|
||||||
string memory newLogo,
|
string memory newLogo,
|
||||||
uint24 newColor
|
uint24 newColor
|
||||||
) public {
|
) public {
|
||||||
|
|
@ -47,7 +49,7 @@ contract Test_FleekERC721_GetToken is Test_FleekERC721_Base {
|
||||||
CuT.setTokenExternalURL(tokenId, newExternalURL);
|
CuT.setTokenExternalURL(tokenId, newExternalURL);
|
||||||
transferENS(newENS, deployer);
|
transferENS(newENS, deployer);
|
||||||
CuT.setTokenENS(tokenId, newENS);
|
CuT.setTokenENS(tokenId, newENS);
|
||||||
CuT.setTokenBuild(tokenId, newCommitHash, newRepository);
|
CuT.setTokenBuild(tokenId, newCommitHash, newRepository, newIpfsHash, newDomain);
|
||||||
CuT.setTokenLogoAndColor(tokenId, newLogo, newColor);
|
CuT.setTokenLogoAndColor(tokenId, newLogo, newColor);
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
"fleek.eth",
|
"fleek.eth",
|
||||||
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
||||||
"https://github.com/a-different/repository",
|
"https://github.com/a-different/repository",
|
||||||
|
"mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a",
|
||||||
TestConstants.LOGO_1,
|
TestConstants.LOGO_1,
|
||||||
0x654321,
|
0x654321,
|
||||||
false,
|
false,
|
||||||
|
|
@ -56,6 +57,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
"fleek.eth",
|
"fleek.eth",
|
||||||
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
||||||
"https://github.com/a-different/repository",
|
"https://github.com/a-different/repository",
|
||||||
|
"mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a",
|
||||||
TestConstants.LOGO_1,
|
TestConstants.LOGO_1,
|
||||||
0x654321,
|
0x654321,
|
||||||
true,
|
true,
|
||||||
|
|
@ -81,6 +83,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
string memory ens,
|
string memory ens,
|
||||||
string memory commitHash,
|
string memory commitHash,
|
||||||
string memory gitRepository,
|
string memory gitRepository,
|
||||||
|
string memory ipfsHash,
|
||||||
string memory logo,
|
string memory logo,
|
||||||
uint24 color,
|
uint24 color,
|
||||||
bool autoApprovalAp
|
bool autoApprovalAp
|
||||||
|
|
@ -95,6 +98,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
ens,
|
ens,
|
||||||
commitHash,
|
commitHash,
|
||||||
gitRepository,
|
gitRepository,
|
||||||
|
ipfsHash,
|
||||||
logo,
|
logo,
|
||||||
color,
|
color,
|
||||||
autoApprovalAp,
|
autoApprovalAp,
|
||||||
|
|
@ -115,6 +119,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
TestConstants.APP_ENS,
|
TestConstants.APP_ENS,
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
false,
|
false,
|
||||||
|
|
@ -131,6 +136,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
||||||
"",
|
"",
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ abstract contract Test_FleekERC721_Base is Test, Test_FleekERC721_Assertions {
|
||||||
TestConstants.APP_ENS,
|
TestConstants.APP_ENS,
|
||||||
TestConstants.APP_COMMIT_HASH,
|
TestConstants.APP_COMMIT_HASH,
|
||||||
TestConstants.APP_GIT_REPOSITORY,
|
TestConstants.APP_GIT_REPOSITORY,
|
||||||
|
TestConstants.APP_IPFS_HASH,
|
||||||
TestConstants.LOGO_0,
|
TestConstants.LOGO_0,
|
||||||
TestConstants.APP_COLOR,
|
TestConstants.APP_COLOR,
|
||||||
false, // Auto Approval Is OFF
|
false, // Auto Approval Is OFF
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import "./TestBase.sol";
|
||||||
|
|
||||||
contract Test_FleekERC721_TokenURIAssertions is Test {
|
contract Test_FleekERC721_TokenURIAssertions is Test {
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, string[2] value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, string[4] value, address indexed triggeredBy);
|
||||||
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
|
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
|
||||||
|
|
||||||
function expectMetadataUpdate(
|
function expectMetadataUpdate(
|
||||||
|
|
@ -22,7 +22,7 @@ contract Test_FleekERC721_TokenURIAssertions is Test {
|
||||||
function expectMetadataUpdate(
|
function expectMetadataUpdate(
|
||||||
uint256 _tokenId,
|
uint256 _tokenId,
|
||||||
string memory key,
|
string memory key,
|
||||||
string[2] memory value,
|
string[4] memory value,
|
||||||
address triggeredBy
|
address triggeredBy
|
||||||
) public {
|
) public {
|
||||||
vm.expectEmit(true, true, true, true);
|
vm.expectEmit(true, true, true, true);
|
||||||
|
|
@ -57,7 +57,13 @@ contract Test_FleekERC721_TokenURI is Test_FleekERC721_Base, Test_FleekERC721_To
|
||||||
CuT.setTokenExternalURL(tokenId, "https://new-url.com");
|
CuT.setTokenExternalURL(tokenId, "https://new-url.com");
|
||||||
transferENS("new-ens.eth", deployer);
|
transferENS("new-ens.eth", deployer);
|
||||||
CuT.setTokenENS(tokenId, "new-ens.eth");
|
CuT.setTokenENS(tokenId, "new-ens.eth");
|
||||||
CuT.setTokenBuild(tokenId, "ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo");
|
CuT.setTokenBuild(
|
||||||
|
tokenId,
|
||||||
|
"ce1a3fc141e29f8e1d00a654e156c4982d7711bf",
|
||||||
|
"https://github.com/other/repo",
|
||||||
|
"ipfsHash",
|
||||||
|
"domain"
|
||||||
|
);
|
||||||
CuT.setTokenLogoAndColor(tokenId, TestConstants.LOGO_1, 0x654321);
|
CuT.setTokenLogoAndColor(tokenId, TestConstants.LOGO_1, 0x654321);
|
||||||
CuT.setTokenVerified(tokenId, true);
|
CuT.setTokenVerified(tokenId, true);
|
||||||
|
|
||||||
|
|
@ -96,10 +102,16 @@ contract Test_FleekERC721_TokenURI is Test_FleekERC721_Base, Test_FleekERC721_To
|
||||||
expectMetadataUpdate(
|
expectMetadataUpdate(
|
||||||
tokenId,
|
tokenId,
|
||||||
"build",
|
"build",
|
||||||
["ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo"],
|
["ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo", "ipfshash", "domain"],
|
||||||
deployer
|
deployer
|
||||||
);
|
);
|
||||||
CuT.setTokenBuild(tokenId, "ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo");
|
CuT.setTokenBuild(
|
||||||
|
tokenId,
|
||||||
|
"ce1a3fc141e29f8e1d00a654e156c4982d7711bf",
|
||||||
|
"https://github.com/other/repo",
|
||||||
|
"ipfshash",
|
||||||
|
"domain"
|
||||||
|
);
|
||||||
|
|
||||||
expectMetadataUpdate(tokenId, "logo", TestConstants.LOGO_1, deployer);
|
expectMetadataUpdate(tokenId, "logo", TestConstants.LOGO_1, deployer);
|
||||||
CuT.setTokenLogo(tokenId, TestConstants.LOGO_1);
|
CuT.setTokenLogo(tokenId, TestConstants.LOGO_1);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ describe('FleekERC721.Billing', () => {
|
||||||
MintParams.ens,
|
MintParams.ens,
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,7 @@ describe('FleekERC721.CollectionRoles', () => {
|
||||||
TestConstants.MintParams.ens,
|
TestConstants.MintParams.ens,
|
||||||
TestConstants.MintParams.commitHash,
|
TestConstants.MintParams.commitHash,
|
||||||
TestConstants.MintParams.gitRepository,
|
TestConstants.MintParams.gitRepository,
|
||||||
|
TestConstants.MintParams.ipfsHash,
|
||||||
TestConstants.MintParams.logo,
|
TestConstants.MintParams.logo,
|
||||||
TestConstants.MintParams.color,
|
TestConstants.MintParams.color,
|
||||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ describe('FleekERC721.ENS', () => {
|
||||||
'app.eth',
|
'app.eth',
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
@ -43,6 +44,7 @@ describe('FleekERC721.ENS', () => {
|
||||||
'app.eth',
|
'app.eth',
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ describe('FleekERC721.GetLastTokenId', () => {
|
||||||
TestConstants.MintParams.ens,
|
TestConstants.MintParams.ens,
|
||||||
TestConstants.MintParams.commitHash,
|
TestConstants.MintParams.commitHash,
|
||||||
TestConstants.MintParams.gitRepository,
|
TestConstants.MintParams.gitRepository,
|
||||||
|
TestConstants.MintParams.ipfsHash,
|
||||||
TestConstants.MintParams.logo,
|
TestConstants.MintParams.logo,
|
||||||
TestConstants.MintParams.color,
|
TestConstants.MintParams.color,
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export const TestConstants = Object.freeze({
|
||||||
externalUrl: 'https://fleek.co',
|
externalUrl: 'https://fleek.co',
|
||||||
commitHash: 'b72e47171746b6a9e29b801af9cb655ecf4d665c',
|
commitHash: 'b72e47171746b6a9e29b801af9cb655ecf4d665c',
|
||||||
gitRepository: 'https://github.com/fleekxyz/non-fungible-apps',
|
gitRepository: 'https://github.com/fleekxyz/non-fungible-apps',
|
||||||
|
ipfsHash: 'mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a',
|
||||||
logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI1MDAiIHdpZHRoPSIyMTgzIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjQgMTQxLjUzMTk5OTk5OTk5OTk4Ij48cGF0aCBkPSJNMTAuMzgzIDEyNi44OTRMMCAwbDEyNCAuMjU1LTEwLjk3OSAxMjYuNjM5LTUwLjU1MyAxNC42Mzh6IiBmaWxsPSIjZTM0ZjI2Ii8+PHBhdGggZD0iTTYyLjQ2OCAxMjkuMjc3VjEyLjA4NWw1MS4wNjQuMTctOS4xMDYgMTA0Ljg1MXoiIGZpbGw9IiNlZjY1MmEiLz48cGF0aCBkPSJNOTkuNDkgNDEuMzYybDEuNDQ2LTE1LjQ5SDIyLjM4M2w0LjM0IDQ3LjQ5aDU0LjIxM0w3OC44MSA5My42MTdsLTE3LjM2MiA0LjY4LTE3LjYxNy01LjEwNi0uOTM2LTEyLjA4NUgyNy4zMTlsMi4xMjggMjQuNjgxIDMyIDguOTM2IDMyLjI1NS04LjkzNiA0LjM0LTQ4LjE3SDQxLjEwN0wzOS40OSA0MS4zNjJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+',
|
logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI1MDAiIHdpZHRoPSIyMTgzIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjQgMTQxLjUzMTk5OTk5OTk5OTk4Ij48cGF0aCBkPSJNMTAuMzgzIDEyNi44OTRMMCAwbDEyNCAuMjU1LTEwLjk3OSAxMjYuNjM5LTUwLjU1MyAxNC42Mzh6IiBmaWxsPSIjZTM0ZjI2Ii8+PHBhdGggZD0iTTYyLjQ2OCAxMjkuMjc3VjEyLjA4NWw1MS4wNjQuMTctOS4xMDYgMTA0Ljg1MXoiIGZpbGw9IiNlZjY1MmEiLz48cGF0aCBkPSJNOTkuNDkgNDEuMzYybDEuNDQ2LTE1LjQ5SDIyLjM4M2w0LjM0IDQ3LjQ5aDU0LjIxM0w3OC44MSA5My42MTdsLTE3LjM2MiA0LjY4LTE3LjYxNy01LjEwNi0uOTM2LTEyLjA4NUgyNy4zMTlsMi4xMjggMjQuNjgxIDMyIDguOTM2IDMyLjI1NS04LjkzNiA0LjM0LTQ4LjE3SDQxLjEwN0wzOS40OSA0MS4zNjJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+',
|
||||||
color: 0xe34f26,
|
color: 0xe34f26,
|
||||||
accessPointAutoApprovalSettings: false,
|
accessPointAutoApprovalSettings: false,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ export const Events = Object.freeze({
|
||||||
MetadataUpdate: {
|
MetadataUpdate: {
|
||||||
string: 'MetadataUpdate(uint256,string,string,address)',
|
string: 'MetadataUpdate(uint256,string,string,address)',
|
||||||
uint24: 'MetadataUpdate(uint256,string,uint24,address)',
|
uint24: 'MetadataUpdate(uint256,string,uint24,address)',
|
||||||
stringTuple: 'MetadataUpdate(uint256,string,string[2],address)',
|
stringArray4: 'MetadataUpdate(uint256,string,string[4],address)',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ export abstract class Fixtures {
|
||||||
TestConstants.MintParams.ens,
|
TestConstants.MintParams.ens,
|
||||||
TestConstants.MintParams.commitHash,
|
TestConstants.MintParams.commitHash,
|
||||||
TestConstants.MintParams.gitRepository,
|
TestConstants.MintParams.gitRepository,
|
||||||
|
TestConstants.MintParams.ipfsHash,
|
||||||
TestConstants.MintParams.logo,
|
TestConstants.MintParams.logo,
|
||||||
TestConstants.MintParams.color,
|
TestConstants.MintParams.color,
|
||||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ describe('FleekERC721.Minting', () => {
|
||||||
MintParams.ens,
|
MintParams.ens,
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
@ -40,6 +41,7 @@ describe('FleekERC721.Minting', () => {
|
||||||
MintParams.ens,
|
MintParams.ens,
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
@ -66,6 +68,7 @@ describe('FleekERC721.Minting', () => {
|
||||||
MintParams.ens,
|
MintParams.ens,
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
@ -87,6 +90,7 @@ describe('FleekERC721.Minting', () => {
|
||||||
'',
|
'',
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
MintParams.accessPointAutoApprovalSettings,
|
MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ describe('FleekERC721.Pausable', () => {
|
||||||
MintParams.ens,
|
MintParams.ens,
|
||||||
MintParams.commitHash,
|
MintParams.commitHash,
|
||||||
MintParams.gitRepository,
|
MintParams.gitRepository,
|
||||||
|
MintParams.ipfsHash,
|
||||||
MintParams.logo,
|
MintParams.logo,
|
||||||
MintParams.color,
|
MintParams.color,
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,20 @@ describe('FleekERC721.UpdateProperties', () => {
|
||||||
it('should emit event for build change', async () => {
|
it('should emit event for build change', async () => {
|
||||||
const { contract, tokenId, owner } = fixture;
|
const { contract, tokenId, owner } = fixture;
|
||||||
|
|
||||||
await expect(contract.setTokenBuild(tokenId, 'commitHash', 'gitRepository'))
|
await expect(
|
||||||
.to.emit(contract, Events.MetadataUpdate.stringTuple)
|
contract.setTokenBuild(
|
||||||
|
tokenId,
|
||||||
|
'commitHash',
|
||||||
|
'gitRepository',
|
||||||
|
'ipfsHash',
|
||||||
|
'domain'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.to.emit(contract, Events.MetadataUpdate.stringArray4)
|
||||||
.withArgs(
|
.withArgs(
|
||||||
tokenId,
|
tokenId,
|
||||||
'build',
|
'build',
|
||||||
['commitHash', 'gitRepository'],
|
['commitHash', 'gitRepository', 'ipfsHash', 'domain'],
|
||||||
owner.address
|
owner.address
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ describe('Deploy', () => {
|
||||||
TestConstants.MintParams.ens,
|
TestConstants.MintParams.ens,
|
||||||
TestConstants.MintParams.commitHash,
|
TestConstants.MintParams.commitHash,
|
||||||
TestConstants.MintParams.gitRepository,
|
TestConstants.MintParams.gitRepository,
|
||||||
|
TestConstants.MintParams.ipfsHash,
|
||||||
TestConstants.MintParams.logo,
|
TestConstants.MintParams.logo,
|
||||||
TestConstants.MintParams.color,
|
TestConstants.MintParams.color,
|
||||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"pinst": "^3.0.0",
|
"pinst": "^3.0.0",
|
||||||
"prettier": "^2.8.4",
|
"prettier": "^2.8.4",
|
||||||
"prettier-plugin-solidity": "^1.0.0",
|
"prettier-plugin-solidity": "^1.0.0",
|
||||||
|
"serverless-offline": "^12.0.4",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,22 @@ To deploy to development environment:
|
||||||
To deploy to production environment:
|
To deploy to production environment:
|
||||||
`yarn sls deploy --stage prd`
|
`yarn sls deploy --stage prd`
|
||||||
|
|
||||||
|
### Running MongoDB
|
||||||
|
|
||||||
|
The first step to run MongoDB is making sure the service is installed on the machine locally. You can check the [official MongoDB website](https://www.mongodb.com/docs/manual/installation/#mongodb-installation-tutorials) for more information on the installation process.
|
||||||
|
|
||||||
|
To process database transactions such as `create` calls, Prisma needs the MongoDB instance to be running as a replica set. Run the commands below to start a replica set with `mongod` and `mongosh`:
|
||||||
|
|
||||||
|
```
|
||||||
|
// You should replace the dbpath with the actual path on your machine and assign a name to your replica set. (Default path on linux is: /var/lib/mongodb)
|
||||||
|
// Do not close the terminal tab after running mongod.
|
||||||
|
$ sudo mongod --port 27017 --dbpath /path/to/db --replSet replicaName --bind_ip localhost,127.0.0.1
|
||||||
|
// Start a mongosh session and run the replica set initiation command in the mongo shell.
|
||||||
|
$ mongosh
|
||||||
|
> rs.initiate()
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure you copy the connection string that is presented in the `Connecting to` field when the mongosh service starts to run. We need the connection string to access the replica set. Rename the `.env.example` file to `.env` and replace the connection string placeholder in the file with the one you copied.
|
||||||
|
|
||||||
### Prisma configuration
|
### Prisma configuration
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
"build": "yarn tsc",
|
"build": "yarn tsc",
|
||||||
"invoke:build": "yarn build && serverless invoke local --function submitBuildInfo",
|
"invoke:build": "yarn build && serverless invoke local --function submitBuildInfo",
|
||||||
"prisma:generate": "npx prisma generate",
|
"prisma:generate": "npx prisma generate",
|
||||||
"prisma:pull": "npx prisma db pull"
|
"prisma:pull": "npx prisma db pull --force",
|
||||||
|
"start": "serverless offline"
|
||||||
},
|
},
|
||||||
"author": "fleek",
|
"author": "fleek",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -30,12 +31,13 @@
|
||||||
"@middy/http-json-body-parser": "^4.2.7",
|
"@middy/http-json-body-parser": "^4.2.7",
|
||||||
"@middy/http-response-serializer": "^4.2.8",
|
"@middy/http-response-serializer": "^4.2.8",
|
||||||
"@prisma/client": "^4.13.0",
|
"@prisma/client": "^4.13.0",
|
||||||
"aws-sdk": "^2.1342.0",
|
|
||||||
"prisma": "^4.13.0",
|
|
||||||
"uuid": "^9.0.0",
|
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
|
"aws-sdk": "^2.1342.0",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"prisma": "^4.13.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
"web3": "^1.9.0"
|
"web3": "^1.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,21 @@ datasource db {
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
model tokens {
|
model builds {
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||||
commit_hash String
|
commitHash String
|
||||||
github_url String
|
domain String
|
||||||
owner String
|
githubRepository String
|
||||||
tokenId Int
|
ipfsHash String
|
||||||
|
}
|
||||||
|
|
||||||
|
model tokens {
|
||||||
|
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||||
|
commitHash String
|
||||||
|
domain String
|
||||||
|
githubRepository String
|
||||||
|
ipfsHash String
|
||||||
|
owner String
|
||||||
|
tokenId Int
|
||||||
|
verified Boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,91 @@
|
||||||
import { APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
|
import { APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
|
||||||
import { formatJSONResponse } from '@libs/api-gateway';
|
import { formatJSONResponse } from '@libs/api-gateway';
|
||||||
const querystring = require('querystring');
|
|
||||||
|
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { nfaContract } from '@libs/nfa-contract';
|
import { prisma } from '@libs/prisma';
|
||||||
|
import { account, nfaContract } from '@libs/nfa-contract';
|
||||||
|
|
||||||
export const submitBuildInfo = async (
|
export const submitBuildInfo = async (
|
||||||
event: APIGatewayEvent
|
event: APIGatewayEvent
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
try {
|
try {
|
||||||
const eventData = querystring.parse(event.body);
|
if (event.body === null) {
|
||||||
|
return formatJSONResponse({
|
||||||
|
status: 422,
|
||||||
|
message: 'Required parameters were not passed.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(event.body);
|
||||||
|
|
||||||
const id = v4();
|
const id = v4();
|
||||||
const buildInfo = {
|
const buildInfo = {
|
||||||
buildId: id,
|
buildId: id,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
submittedData: eventData,
|
githubRepository: data.githubRepository,
|
||||||
|
commitHash: data.commitHash,
|
||||||
|
ipfsHash: data.ipfsHash,
|
||||||
|
domain: data.domain,
|
||||||
};
|
};
|
||||||
|
|
||||||
// place holder call
|
// Add build record to the database, if it's not already added
|
||||||
nfaContract.methods
|
const buildRecord = await prisma.builds.findMany({
|
||||||
.setTokenBuild(1, 'hash', 'repo')
|
where: {
|
||||||
.call((err: string | undefined, res: any) => {
|
commitHash: buildInfo.commitHash,
|
||||||
if (err) throw new Error(err);
|
githubRepository: buildInfo.githubRepository,
|
||||||
console.log('result');
|
ipfsHash: buildInfo.ipfsHash,
|
||||||
console.log(res);
|
domain: buildInfo.domain,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (buildRecord.length == 0) {
|
||||||
|
await prisma.builds.create({
|
||||||
|
data: {
|
||||||
|
githubRepository: buildInfo.githubRepository,
|
||||||
|
commitHash: buildInfo.commitHash,
|
||||||
|
ipfsHash: buildInfo.ipfsHash,
|
||||||
|
domain: buildInfo.domain,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const mintRecord = await prisma.tokens.findMany({
|
||||||
|
where: {
|
||||||
|
ipfsHash: buildInfo.ipfsHash,
|
||||||
|
domain: buildInfo.domain,
|
||||||
|
commitHash: buildInfo.commitHash,
|
||||||
|
githubRepository: buildInfo.githubRepository,
|
||||||
|
verified: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mintRecord.length > 0) {
|
||||||
|
// Trigger verification
|
||||||
|
|
||||||
|
// Mark the token as verified in the contract
|
||||||
|
// call the `setTokenVerified` method
|
||||||
|
await nfaContract.methods
|
||||||
|
.setTokenVerified(mintRecord[0].tokenId, true)
|
||||||
|
.send({
|
||||||
|
from: account.address,
|
||||||
|
gas: '1000000',
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
|
||||||
|
// Update the database record in the tokens collection
|
||||||
|
await prisma.tokens.updateMany({
|
||||||
|
where: {
|
||||||
|
ipfsHash: buildInfo.ipfsHash,
|
||||||
|
domain: buildInfo.domain,
|
||||||
|
commitHash: buildInfo.commitHash,
|
||||||
|
githubRepository: buildInfo.githubRepository,
|
||||||
|
verified: false,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
verified: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return formatJSONResponse({
|
return formatJSONResponse({
|
||||||
buildInfo,
|
buildInfo,
|
||||||
|
|
|
||||||
|
|
@ -6,31 +6,185 @@ import {
|
||||||
import { formatJSONResponse } from '@libs/api-gateway';
|
import { formatJSONResponse } from '@libs/api-gateway';
|
||||||
|
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
import { initPrisma, prisma } from '@libs/prisma';
|
||||||
|
import { account, nfaContract, web3 } from '@libs/nfa-contract';
|
||||||
|
|
||||||
export const submitMintInfo = async (
|
export const submitMintInfo = async (
|
||||||
event: APIGatewayEvent
|
event: APIGatewayEvent
|
||||||
///context: APIGatewayEventRequestContext
|
///context: APIGatewayEventRequestContext
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
try {
|
try {
|
||||||
|
if (event.body === null) {
|
||||||
|
return formatJSONResponse({
|
||||||
|
status: 422,
|
||||||
|
message: 'Required parameters were not passed.',
|
||||||
|
});
|
||||||
|
}
|
||||||
const id = v4();
|
const id = v4();
|
||||||
|
|
||||||
/**if (!verifyAlchemySig(event.headers.xalchemywork)) {
|
/**if (!verifyAlchemySig(event.headers.xalchemywork)) {
|
||||||
throw new Error('Invalid sig');
|
throw new Error('Invalid sig');
|
||||||
}**/
|
}**/
|
||||||
|
|
||||||
if (event.body == undefined) {
|
const eventBody = JSON.parse(event.body);
|
||||||
throw new Error('Undefined data');
|
const topics = eventBody.event.data.block.logs[1].slice(1, 3);
|
||||||
}
|
const hexCalldata = eventBody.event.data.block.logs[1].data;
|
||||||
|
|
||||||
|
const decodedLogs = web3.eth.abi.decodeLog(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
indexed: true,
|
||||||
|
internalType: 'uint256',
|
||||||
|
name: 'tokenId',
|
||||||
|
type: 'uint256',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'name',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'description',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'externalURL',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'ENS',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'commitHash',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'gitRepository',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'ipfsHash',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'string',
|
||||||
|
name: 'logo',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'uint24',
|
||||||
|
name: 'color',
|
||||||
|
type: 'uint24',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'bool',
|
||||||
|
name: 'accessPointAutoApproval',
|
||||||
|
type: 'bool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: true,
|
||||||
|
internalType: 'address',
|
||||||
|
name: 'minter',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: true,
|
||||||
|
internalType: 'address',
|
||||||
|
name: 'owner',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
indexed: false,
|
||||||
|
internalType: 'address',
|
||||||
|
name: 'verifier',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hexCalldata,
|
||||||
|
topics
|
||||||
|
);
|
||||||
|
|
||||||
const mintInfo = {
|
const mintInfo = {
|
||||||
buildId: id,
|
mintId: id,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
body: JSON.parse(event.body),
|
tokenId: decodedLogs.tokenId,
|
||||||
|
githubRepository: decodedLogs.gitRepository,
|
||||||
|
commit_hash: decodedLogs.commitHash,
|
||||||
|
owner: decodedLogs.owner,
|
||||||
|
ipfsHash: decodedLogs.ipfsHash,
|
||||||
|
domain: decodedLogs.externalURL,
|
||||||
};
|
};
|
||||||
|
|
||||||
// check if we have it in mongo
|
initPrisma();
|
||||||
// if so, trigger verification call
|
|
||||||
// if not, add to mongo
|
// Check if there is any build associated with the repository, commit hash, tokenId, and ipfsHash
|
||||||
|
|
||||||
|
const build = await prisma.builds.findMany({
|
||||||
|
where: {
|
||||||
|
githubRepository: mintInfo.githubRepository,
|
||||||
|
commitHash: mintInfo.commit_hash,
|
||||||
|
ipfsHash: mintInfo.ipfsHash,
|
||||||
|
domain: mintInfo.domain,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let verified = false;
|
||||||
|
|
||||||
|
if (build.length > 0) {
|
||||||
|
// Mark the token as verified in the contract
|
||||||
|
try {
|
||||||
|
// call the `setTokenVerified` method
|
||||||
|
await nfaContract.methods
|
||||||
|
.setTokenVerified(mintInfo.tokenId, true)
|
||||||
|
.send({
|
||||||
|
from: account.address,
|
||||||
|
gas: '1000000',
|
||||||
|
});
|
||||||
|
verified = true;
|
||||||
|
} catch (error) {
|
||||||
|
// catch transaction error
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the record to the database
|
||||||
|
|
||||||
|
const token = await prisma.tokens.findMany({
|
||||||
|
where: {
|
||||||
|
tokenId: Number(mintInfo.tokenId),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (token.length == 0) {
|
||||||
|
await prisma.tokens.create({
|
||||||
|
data: {
|
||||||
|
tokenId: Number(mintInfo.tokenId),
|
||||||
|
githubRepository: mintInfo.githubRepository,
|
||||||
|
commitHash: mintInfo.commit_hash,
|
||||||
|
owner: mintInfo.owner,
|
||||||
|
ipfsHash: mintInfo.ipfsHash,
|
||||||
|
verified: verified,
|
||||||
|
domain: mintInfo.domain,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return formatJSONResponse({
|
return formatJSONResponse({
|
||||||
mintInfo,
|
mintInfo,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
import Web3 from 'web3';
|
import Web3 from 'web3';
|
||||||
import * as abiFile from '../../../contracts/deployments/goerli/FleekERC721.json';
|
import * as abiFile from '../../../contracts/deployments/goerli/FleekERC721.json';
|
||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
if (process.env.PRIVATE_KEY === undefined) {
|
||||||
|
throw Error('Private key environment variable not set.');
|
||||||
|
}
|
||||||
|
|
||||||
const contract_address = abiFile.address;
|
const contract_address = abiFile.address;
|
||||||
const abi = abiFile.abi as any;
|
export const abi = abiFile.abi as any;
|
||||||
|
|
||||||
const web3 = new Web3('https://rpc.goerli.mudit.blog');
|
|
||||||
|
|
||||||
|
export const web3 = new Web3('https://rpc.goerli.mudit.blog');
|
||||||
export const nfaContract = new web3.eth.Contract(abi, contract_address);
|
export const nfaContract = new web3.eth.Contract(abi, contract_address);
|
||||||
|
export const account = web3.eth.accounts.privateKeyToAccount(
|
||||||
|
process.env.PRIVATE_KEY
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ export async function initPrisma() {
|
||||||
initPrisma()
|
initPrisma()
|
||||||
.catch(async (e) => {
|
.catch(async (e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
})
|
|
||||||
.finally(async () => {
|
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect();
|
||||||
|
process.exit(1);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
prisma.$disconnect();
|
||||||
});
|
});
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"target": "es2016",
|
"target": "es2016",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"esModuleInterop": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
|
||||||
|
|
@ -1588,7 +1588,7 @@
|
||||||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz"
|
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz"
|
||||||
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
||||||
|
|
||||||
"@types/node@*", "@types/node@^18.15.5":
|
"@types/node@*":
|
||||||
version "18.15.5"
|
version "18.15.5"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz"
|
||||||
integrity sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==
|
integrity sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==
|
||||||
|
|
@ -1598,6 +1598,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
|
||||||
integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
|
integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
|
||||||
|
|
||||||
|
"@types/node@^18.15.11":
|
||||||
|
version "18.16.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.1.tgz#5db121e9c5352925bb1f1b892c4ae620e3526799"
|
||||||
|
integrity sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==
|
||||||
|
|
||||||
"@types/pbkdf2@^3.0.0":
|
"@types/pbkdf2@^3.0.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1"
|
resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1"
|
||||||
|
|
@ -2767,7 +2772,7 @@ dotenv-expand@^9.0.0:
|
||||||
|
|
||||||
dotenv@^16.0.3:
|
dotenv@^16.0.3:
|
||||||
version "16.0.3"
|
version "16.0.3"
|
||||||
resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
|
||||||
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
||||||
|
|
||||||
duration@^0.2.2:
|
duration@^0.2.2:
|
||||||
|
|
@ -6262,10 +6267,10 @@ typedarray-to-buffer@^3.1.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-typedarray "^1.0.0"
|
is-typedarray "^1.0.0"
|
||||||
|
|
||||||
typescript@^5.0.2:
|
typescript@^5.0.4:
|
||||||
version "5.0.2"
|
version "5.0.4"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
||||||
integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==
|
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
||||||
|
|
||||||
ultron@~1.1.0:
|
ultron@~1.1.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type NewMint @entity(immutable: true) {
|
||||||
ENS: String!
|
ENS: String!
|
||||||
commitHash: String! # string
|
commitHash: String! # string
|
||||||
gitRepository: String! # string
|
gitRepository: String! # string
|
||||||
|
ipfsHash: String!
|
||||||
logo: String!
|
logo: String!
|
||||||
color: Int!
|
color: Int!
|
||||||
accessPointAutoApproval: Boolean!
|
accessPointAutoApproval: Boolean!
|
||||||
|
|
@ -44,7 +45,7 @@ type MetadataUpdate @entity(immutable: true) {
|
||||||
key: String!
|
key: String!
|
||||||
stringValue: String
|
stringValue: String
|
||||||
uint24Value: Int
|
uint24Value: Int
|
||||||
doubleStringValue: [String!]!
|
multipleStringValue: [String!]!
|
||||||
booleanValue: Boolean
|
booleanValue: Boolean
|
||||||
byAddress: Bytes!
|
byAddress: Bytes!
|
||||||
blockNumber: BigInt!
|
blockNumber: BigInt!
|
||||||
|
|
@ -76,12 +77,20 @@ type Token @entity {
|
||||||
owner: Owner!
|
owner: Owner!
|
||||||
mintedBy: Bytes!
|
mintedBy: Bytes!
|
||||||
controllers: [Controller!]
|
controllers: [Controller!]
|
||||||
gitRepository: GitRepository!
|
|
||||||
commitHash: String!
|
|
||||||
accessPoints: [AccessPoint!] @derivedFrom(field: "token")
|
accessPoints: [AccessPoint!] @derivedFrom(field: "token")
|
||||||
verifier: Verifier # Address
|
verifier: Verifier # Address
|
||||||
verified: Boolean!
|
verified: Boolean!
|
||||||
createdAt: BigInt!
|
createdAt: BigInt!
|
||||||
|
builds: [Build!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Build @entity {
|
||||||
|
id: Bytes! # Token ID
|
||||||
|
gitRepository: GitRepository!
|
||||||
|
commitHash: String!
|
||||||
|
ipfsHash: String!
|
||||||
|
domain: String!
|
||||||
|
token: Token! @derivedFrom(field: "builds")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Owner entity for collection, access points, and tokens
|
# Owner entity for collection, access points, and tokens
|
||||||
|
|
@ -106,7 +115,7 @@ type Verifier @entity {
|
||||||
|
|
||||||
type GitRepository @entity {
|
type GitRepository @entity {
|
||||||
id: String! # transaction hash of the first transaction this repository appeared in
|
id: String! # transaction hash of the first transaction this repository appeared in
|
||||||
tokens: [Token!] @derivedFrom(field: "gitRepository")
|
builds: [Build!] @derivedFrom(field: "gitRepository")
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccessPoint @entity {
|
type AccessPoint @entity {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
GitRepository as GitRepositoryEntity,
|
GitRepository as GitRepositoryEntity,
|
||||||
MetadataUpdate,
|
MetadataUpdate,
|
||||||
Token,
|
Token,
|
||||||
|
Build,
|
||||||
} from '../generated/schema';
|
} from '../generated/schema';
|
||||||
|
|
||||||
export function handleMetadataUpdateWithStringValue(
|
export function handleMetadataUpdateWithStringValue(
|
||||||
|
|
@ -61,7 +62,7 @@ export function handleMetadataUpdateWithStringValue(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleMetadataUpdateWithDoubleStringValue(
|
export function handleMetadataUpdateWithMultipleStringValues(
|
||||||
event: MetadataUpdateEvent3
|
event: MetadataUpdateEvent3
|
||||||
): void {
|
): void {
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,30 +74,29 @@ export function handleMetadataUpdateWithDoubleStringValue(
|
||||||
|
|
||||||
entity.key = event.params.key;
|
entity.key = event.params.key;
|
||||||
entity.tokenId = event.params._tokenId;
|
entity.tokenId = event.params._tokenId;
|
||||||
entity.doubleStringValue = event.params.value;
|
entity.multipleStringValue = event.params.value;
|
||||||
entity.blockNumber = event.block.number;
|
entity.blockNumber = event.block.number;
|
||||||
entity.blockTimestamp = event.block.timestamp;
|
entity.blockTimestamp = event.block.timestamp;
|
||||||
entity.transactionHash = event.transaction.hash;
|
entity.transactionHash = event.transaction.hash;
|
||||||
|
|
||||||
entity.save();
|
entity.save();
|
||||||
|
|
||||||
// UPDATE TOKEN
|
// CREATE BUILD
|
||||||
const token = Token.load(
|
const build = new Build(
|
||||||
Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId))
|
Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId))
|
||||||
);
|
);
|
||||||
|
if (event.params.key == 'build') {
|
||||||
if (token) {
|
let gitRepositoryEntity = GitRepositoryEntity.load(event.params.value[1]);
|
||||||
if (event.params.key == 'build') {
|
if (!gitRepositoryEntity) {
|
||||||
let gitRepositoryEntity = GitRepositoryEntity.load(event.params.value[1]);
|
// Create a new gitRepository entity
|
||||||
if (!gitRepositoryEntity) {
|
gitRepositoryEntity = new GitRepositoryEntity(event.params.value[1]);
|
||||||
// Create a new gitRepository entity
|
|
||||||
gitRepositoryEntity = new GitRepositoryEntity(event.params.value[1]);
|
|
||||||
}
|
|
||||||
token.commitHash = event.params.value[0];
|
|
||||||
token.gitRepository = event.params.value[1];
|
|
||||||
token.save();
|
|
||||||
gitRepositoryEntity.save();
|
|
||||||
}
|
}
|
||||||
|
build.commitHash = event.params.value[0];
|
||||||
|
build.gitRepository = event.params.value[1];
|
||||||
|
build.ipfsHash = event.params.value[2];
|
||||||
|
build.domain = event.params.value[3];
|
||||||
|
build.save();
|
||||||
|
gitRepositoryEntity.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export function handleNewMint(event: NewMintEvent): void {
|
||||||
const externalURL = event.params.externalURL;
|
const externalURL = event.params.externalURL;
|
||||||
const ENS = event.params.ENS;
|
const ENS = event.params.ENS;
|
||||||
const gitRepository = event.params.gitRepository;
|
const gitRepository = event.params.gitRepository;
|
||||||
|
const ipfsHash = event.params.ipfsHash;
|
||||||
const commitHash = event.params.commitHash;
|
const commitHash = event.params.commitHash;
|
||||||
const logo = event.params.logo;
|
const logo = event.params.logo;
|
||||||
const color = event.params.color;
|
const color = event.params.color;
|
||||||
|
|
@ -38,6 +39,7 @@ export function handleNewMint(event: NewMintEvent): void {
|
||||||
newMintEntity.ENS = ENS;
|
newMintEntity.ENS = ENS;
|
||||||
newMintEntity.commitHash = commitHash;
|
newMintEntity.commitHash = commitHash;
|
||||||
newMintEntity.gitRepository = gitRepository;
|
newMintEntity.gitRepository = gitRepository;
|
||||||
|
newMintEntity.ipfsHash = ipfsHash;
|
||||||
newMintEntity.logo = logo;
|
newMintEntity.logo = logo;
|
||||||
newMintEntity.color = color;
|
newMintEntity.color = color;
|
||||||
newMintEntity.accessPointAutoApproval = accessPointAutoApproval;
|
newMintEntity.accessPointAutoApproval = accessPointAutoApproval;
|
||||||
|
|
@ -68,8 +70,6 @@ export function handleNewMint(event: NewMintEvent): void {
|
||||||
token.description = description;
|
token.description = description;
|
||||||
token.externalURL = externalURL;
|
token.externalURL = externalURL;
|
||||||
token.ENS = ENS;
|
token.ENS = ENS;
|
||||||
token.gitRepository = gitRepository;
|
|
||||||
token.commitHash = commitHash;
|
|
||||||
token.logo = logo;
|
token.logo = logo;
|
||||||
token.color = color;
|
token.color = color;
|
||||||
token.accessPointAutoApproval = accessPointAutoApproval;
|
token.accessPointAutoApproval = accessPointAutoApproval;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ dataSources:
|
||||||
- ChangeAccessPointAutoApproval
|
- ChangeAccessPointAutoApproval
|
||||||
abis:
|
abis:
|
||||||
- name: FleekNFA
|
- name: FleekNFA
|
||||||
file: ../contracts/deployments/goerli/FleekERC721.json
|
file: ../contracts/artifacts/contracts/FleekERC721.sol/FleekERC721.json
|
||||||
eventHandlers:
|
eventHandlers:
|
||||||
- event: Approval(indexed address,indexed address,indexed uint256)
|
- event: Approval(indexed address,indexed address,indexed uint256)
|
||||||
handler: handleApproval
|
handler: handleApproval
|
||||||
|
|
@ -41,13 +41,13 @@ dataSources:
|
||||||
# Token Events
|
# Token Events
|
||||||
- event: MetadataUpdate(indexed uint256,string,string,indexed address)
|
- event: MetadataUpdate(indexed uint256,string,string,indexed address)
|
||||||
handler: handleMetadataUpdateWithStringValue
|
handler: handleMetadataUpdateWithStringValue
|
||||||
- event: MetadataUpdate(indexed uint256,string,string[2],indexed address)
|
- event: MetadataUpdate(indexed uint256,string,string[4],indexed address)
|
||||||
handler: handleMetadataUpdateWithDoubleStringValue
|
handler: handleMetadataUpdateWithMultipleStringValues
|
||||||
- event: MetadataUpdate(indexed uint256,string,uint24,indexed address)
|
- event: MetadataUpdate(indexed uint256,string,uint24,indexed address)
|
||||||
handler: handleMetadataUpdateWithIntValue
|
handler: handleMetadataUpdateWithIntValue
|
||||||
- event: MetadataUpdate(indexed uint256,string,bool,indexed address)
|
- event: MetadataUpdate(indexed uint256,string,bool,indexed address)
|
||||||
handler: handleMetadataUpdateWithBooleanValue
|
handler: handleMetadataUpdateWithBooleanValue
|
||||||
- event: NewMint(indexed uint256,string,string,string,string,string,string,string,uint24,bool,indexed address,indexed address,address)
|
- event: NewMint(indexed uint256,string,string,string,string,string,string,string,string,uint24,bool,indexed address,indexed address,address)
|
||||||
handler: handleNewMint
|
handler: handleNewMint
|
||||||
- event: Transfer(indexed address,indexed address,indexed uint256)
|
- event: Transfer(indexed address,indexed address,indexed uint256)
|
||||||
handler: handleTransfer
|
handler: handleTransfer
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ query lastNFAsPaginated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query totalTokens($contractId: ID!) {
|
||||||
|
collection(id: $contractId) {
|
||||||
|
totalTokens
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query getNFADetail($id: ID!) {
|
query getNFADetail($id: ID!) {
|
||||||
token(id: $id) {
|
token(id: $id) {
|
||||||
accessPoints {
|
accessPoints {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"dev:css": "tailwindcss -o ./tailwind.css --watch && yarn dev",
|
"dev:css": "tailwindcss -o ./tailwind.css --watch && yarn dev",
|
||||||
"build": "yarn graphclient build && vite build",
|
"build:graph": "yarn graphclient build",
|
||||||
|
"build": "yarn build:graph && vite build",
|
||||||
"postinstall": "graphclient build",
|
"postinstall": "graphclient build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"prod": "yarn build && npx serve dist -s"
|
"prod": "yarn build && npx serve dist -s"
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,8 @@ export abstract class CardStyles {
|
||||||
borderWidth: '$default',
|
borderWidth: '$default',
|
||||||
});
|
});
|
||||||
|
|
||||||
static readonly Heading = styled('h3', {
|
static readonly Header = styled('div', {
|
||||||
color: '$slate12',
|
width: '$full',
|
||||||
fontSize: '$xl',
|
|
||||||
fontWeight: '$medium',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
static readonly Body = styled('div', {
|
static readonly Body = styled('div', {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import React, { forwardRef } from 'react';
|
import React, { forwardRef } from 'react';
|
||||||
|
|
||||||
import { Flex } from '../layout';
|
|
||||||
import { CardStyles } from './card.styles';
|
import { CardStyles } from './card.styles';
|
||||||
|
|
||||||
export abstract class Card {
|
export abstract class Card {
|
||||||
|
|
@ -15,21 +14,7 @@ export abstract class Card {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
static readonly Heading = forwardRef<HTMLHeadingElement, Card.HeadingProps>(
|
static readonly Header = CardStyles.Header;
|
||||||
({ title, leftIcon, rightIcon, css, ...props }, ref) => {
|
|
||||||
return (
|
|
||||||
<Flex css={{ justifyContent: 'space-between', ...css }}>
|
|
||||||
<Flex>
|
|
||||||
{leftIcon}
|
|
||||||
<CardStyles.Heading ref={ref} {...props}>
|
|
||||||
{title}
|
|
||||||
</CardStyles.Heading>
|
|
||||||
</Flex>
|
|
||||||
{rightIcon}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
static readonly Body = forwardRef<HTMLDivElement, Card.BodyProps>(
|
static readonly Body = forwardRef<HTMLDivElement, Card.BodyProps>(
|
||||||
({ children, ...props }, ref) => {
|
({ children, ...props }, ref) => {
|
||||||
|
|
@ -57,12 +42,7 @@ export namespace Card {
|
||||||
typeof CardStyles.Container
|
typeof CardStyles.Container
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type HeadingProps = {
|
export type HeadingProps = React.ComponentProps<typeof CardStyles.Header>;
|
||||||
title: string;
|
|
||||||
css?: React.CSSProperties;
|
|
||||||
leftIcon?: React.ReactNode;
|
|
||||||
rightIcon?: React.ReactNode;
|
|
||||||
} & React.ComponentProps<typeof CardStyles.Heading>;
|
|
||||||
|
|
||||||
export type BodyProps = React.ComponentProps<typeof CardStyles.Body>;
|
export type BodyProps = React.ComponentProps<typeof CardStyles.Body>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Card, Flex } from '@/components';
|
||||||
|
import { styled } from '@/theme';
|
||||||
|
|
||||||
|
export const CustomCardStyles = {
|
||||||
|
Container: styled(Card.Container, {
|
||||||
|
maxWidth: '$107h',
|
||||||
|
}),
|
||||||
|
Title: {
|
||||||
|
Container: styled(Flex, {
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}),
|
||||||
|
Text: styled('h3', {
|
||||||
|
color: '$slate12',
|
||||||
|
fontSize: '$xl',
|
||||||
|
fontWeight: '$medium',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Card, Flex, Icon, IconButton } from '@/components';
|
||||||
|
import { forwardStyledRef } from '@/theme';
|
||||||
|
|
||||||
|
import { CardStyles } from '../card.styles';
|
||||||
|
import { CustomCardStyles as S } from './custom-card.styles';
|
||||||
|
|
||||||
|
export const CustomCardContainer = S.Container;
|
||||||
|
|
||||||
|
export abstract class CustomCardHeader {
|
||||||
|
static readonly Default = forwardStyledRef<
|
||||||
|
HTMLHeadingElement,
|
||||||
|
CustomCard.HeadingProps
|
||||||
|
>(({ title, onClickBack, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Card.Header ref={ref} {...props}>
|
||||||
|
<S.Title.Container>
|
||||||
|
<Flex css={{ gap: '$2' }}>
|
||||||
|
{onClickBack && (
|
||||||
|
<IconButton
|
||||||
|
aria-label="back"
|
||||||
|
colorScheme="gray"
|
||||||
|
variant="link"
|
||||||
|
icon={<Icon name="back" />}
|
||||||
|
onClick={onClickBack}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<S.Title.Text>{title}</S.Title.Text>
|
||||||
|
</Flex>
|
||||||
|
<IconButton
|
||||||
|
aria-label="Add"
|
||||||
|
colorScheme="gray"
|
||||||
|
variant="link"
|
||||||
|
icon={<Icon name="info" />}
|
||||||
|
/>
|
||||||
|
</S.Title.Container>
|
||||||
|
</Card.Header>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
static readonly Success = forwardStyledRef<
|
||||||
|
HTMLHeadingElement,
|
||||||
|
Omit<CustomCard.HeadingProps, 'onClickBack'>
|
||||||
|
>(({ title, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Card.Header ref={ref} {...props}>
|
||||||
|
<Flex css={{ gap: '$2' }}>
|
||||||
|
<Icon
|
||||||
|
name="check-circle"
|
||||||
|
css={{ color: '$green11', fontSize: '$xl' }}
|
||||||
|
/>
|
||||||
|
<S.Title.Text>{title}</S.Title.Text>
|
||||||
|
</Flex>
|
||||||
|
</Card.Header>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace CustomCard {
|
||||||
|
export type ContainerProps = React.ComponentProps<typeof S.Container>;
|
||||||
|
|
||||||
|
export type HeadingProps = {
|
||||||
|
title: string;
|
||||||
|
onClickBack?: () => void;
|
||||||
|
} & React.ComponentProps<typeof CardStyles.Header>;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './custom-card';
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export * from './card';
|
export * from './card';
|
||||||
|
export * from './custom-card';
|
||||||
|
|
|
||||||
|
|
@ -126,17 +126,6 @@ const getButtonCompoundVariant = ({
|
||||||
'&:focus, &:active': {
|
'&:focus, &:active': {
|
||||||
backgroundColor: `$${color}3`,
|
backgroundColor: `$${color}3`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'&:disabled': {
|
|
||||||
backgroundColor: `initial`,
|
|
||||||
'&:hover': {
|
|
||||||
color: `$${color}11`,
|
|
||||||
backgroundColor: `initial`,
|
|
||||||
},
|
|
||||||
'& img, & svg': {
|
|
||||||
filter: 'grayscale(100%)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,11 @@ export abstract class PageStyles {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
minHeight: '85vh',
|
minHeight: '85vh',
|
||||||
maxWidth: '$6xl',
|
maxWidth: '$6xl',
|
||||||
padding: '0 $6',
|
padding: '$6',
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
display: 'grid',
|
|
||||||
|
'@md': {
|
||||||
|
padding: '0 $6',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Text } from '@/components';
|
||||||
import { keyframes, styled } from '@/theme';
|
import { keyframes, styled } from '@/theme';
|
||||||
|
|
||||||
const Loading = keyframes({
|
const Loading = keyframes({
|
||||||
|
|
@ -13,7 +14,7 @@ const Loading = keyframes({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ResolvedAddressStyles = {
|
export const ResolvedAddressStyles = {
|
||||||
Container: styled('span', {
|
Container: styled(Text, {
|
||||||
'&[data-loading="true"]': {
|
'&[data-loading="true"]': {
|
||||||
animation: `${Loading} 1s ease-in-out infinite`,
|
animation: `${Loading} 1s ease-in-out infinite`,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
export const media = {
|
export const media = {
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
|
xs: '(min-width: 375px)',
|
||||||
sm: '(min-width: 640px)',
|
sm: '(min-width: 640px)',
|
||||||
md: '(min-width: 768px)',
|
md: '(min-width: 768px)',
|
||||||
lg: '(min-width: 1024px)',
|
lg: '(min-width: 1024px)',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
import { Card, Flex, Icon, IconButton, Stepper } from '@/components';
|
import {
|
||||||
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
Stepper,
|
||||||
|
} from '@/components';
|
||||||
|
|
||||||
import { CreateAccessPointFormBody } from './create-ap-form-body';
|
import { CreateAccessPointFormBody } from './create-ap-form-body';
|
||||||
|
|
||||||
|
|
@ -6,28 +12,8 @@ export const CreateAccessPointForm: React.FC = () => {
|
||||||
const { prevStep } = Stepper.useContext();
|
const { prevStep } = Stepper.useContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<Card.Heading
|
<CustomCardHeader.Default title="Enter Domain" onClickBack={prevStep} />
|
||||||
title="Enter Domain"
|
|
||||||
leftIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="back" />}
|
|
||||||
css={{ mr: '$2' }}
|
|
||||||
onClick={prevStep}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Flex
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
|
|
@ -38,6 +24,6 @@ export const CreateAccessPointForm: React.FC = () => {
|
||||||
<CreateAccessPointFormBody />
|
<CreateAccessPointFormBody />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { Button, Card, Grid, SpinnerDot, Stepper, Text } from '@/components';
|
import { Button, Card, Flex, SpinnerDot, Stepper, Text } from '@/components';
|
||||||
import { bunnyCDNActions, useAppDispatch, useBunnyCDNStore } from '@/store';
|
import { bunnyCDNActions, useAppDispatch, useBunnyCDNStore } from '@/store';
|
||||||
|
|
||||||
import { useAccessPointFormContext } from '../ap-form-step';
|
import { useAccessPointFormContext } from '../ap-form-step';
|
||||||
|
|
@ -49,9 +49,10 @@ export const APRecordCardBody: React.FC = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
) : (
|
) : (
|
||||||
<Grid
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
rowGap: '$6',
|
gap: '$6',
|
||||||
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text>
|
<Text>
|
||||||
|
|
@ -73,7 +74,7 @@ export const APRecordCardBody: React.FC = () => {
|
||||||
>
|
>
|
||||||
I added the record
|
I added the record
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,9 @@
|
||||||
import { Card, Icon, IconButton, Stepper } from '@/components';
|
import { CustomCardHeader, Stepper } from '@/components';
|
||||||
|
|
||||||
export const APRecordCardHeader: React.FC = () => {
|
export const APRecordCardHeader: React.FC = () => {
|
||||||
const { prevStep } = Stepper.useContext();
|
const { prevStep } = Stepper.useContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Heading
|
<CustomCardHeader.Default title="Create Record" onClickBack={prevStep} />
|
||||||
title="Create Record"
|
|
||||||
leftIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="back" />}
|
|
||||||
css={{ mr: '$2' }}
|
|
||||||
onClick={prevStep}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { Card } from '@/components';
|
import { CustomCardContainer } from '@/components';
|
||||||
|
|
||||||
import { APRecordCardBody } from './ap-record-body';
|
import { APRecordCardBody } from './ap-record-body';
|
||||||
import { APRecordCardHeader } from './ap-record-header';
|
import { APRecordCardHeader } from './ap-record-header';
|
||||||
|
|
||||||
export const APRecordStep: React.FC = () => {
|
export const APRecordStep: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<APRecordCardHeader />
|
<APRecordCardHeader />
|
||||||
<APRecordCardBody />
|
<APRecordCardBody />
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import { useAccount } from 'wagmi';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
Flex,
|
Flex,
|
||||||
Icon,
|
|
||||||
IconButton,
|
|
||||||
ResolvedAddress,
|
ResolvedAddress,
|
||||||
Stepper,
|
Stepper,
|
||||||
Text,
|
Text,
|
||||||
|
|
@ -40,7 +40,9 @@ export const AccessPointDataFragment: React.FC = () => {
|
||||||
label="Owner"
|
label="Owner"
|
||||||
value={
|
value={
|
||||||
address ? (
|
address ? (
|
||||||
<ResolvedAddress truncated={false}>{address || ''}</ResolvedAddress>
|
<ResolvedAddress truncated={false} ellipsis>
|
||||||
|
{address}
|
||||||
|
</ResolvedAddress>
|
||||||
) : (
|
) : (
|
||||||
'Please connect to wallet'
|
'Please connect to wallet'
|
||||||
)
|
)
|
||||||
|
|
@ -111,28 +113,8 @@ export const CreateAccessPointPreview: React.FC = () => {
|
||||||
}, [writeStatus, transactionStatus]);
|
}, [writeStatus, transactionStatus]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<Card.Heading
|
<CustomCardHeader.Default title="Review Details" onClickBack={prevStep} />
|
||||||
title="Review Details"
|
|
||||||
leftIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="back" />}
|
|
||||||
css={{ mr: '$2' }}
|
|
||||||
onClick={prevStep}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
||||||
<AccessPointDataFragment />
|
<AccessPointDataFragment />
|
||||||
|
|
@ -148,6 +130,6 @@ export const CreateAccessPointPreview: React.FC = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { CustomCardContainer } from '@/components';
|
||||||
|
import { keyframes, styled } from '@/theme';
|
||||||
|
|
||||||
|
const CardKeyFrames = keyframes({
|
||||||
|
'0%': { opacity: 0 },
|
||||||
|
'100%': { opacity: 1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CreateApSuccessStyles = {
|
||||||
|
Container: styled(CustomCardContainer, {
|
||||||
|
animation: `${CardKeyFrames} 0.5s ease-in-out 0s`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
@ -1,29 +1,14 @@
|
||||||
import { Button, Card, Flex, Icon, IconButton, Text } from '@/components';
|
import { Button, Card, CustomCardHeader, Flex, Icon, Text } from '@/components';
|
||||||
|
|
||||||
import { CreateAccessPoint } from './create-ap.context';
|
import { CreateAccessPoint } from '../create-ap.context';
|
||||||
import { AccessPointDataFragment } from './create-ap-preview';
|
import { AccessPointDataFragment } from '../create-ap-preview';
|
||||||
|
import { CreateApSuccessStyles as S } from './create-ap-success.styles';
|
||||||
|
|
||||||
export const CreateAccessPointSuccess: React.FC = () => {
|
export const CreateAccessPointSuccess: React.FC = () => {
|
||||||
const { nfa } = CreateAccessPoint.useContext();
|
const { nfa } = CreateAccessPoint.useContext();
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<S.Container>
|
||||||
<Card.Heading
|
<CustomCardHeader.Success title="Hosting Successful" />
|
||||||
title="Hosting Successful"
|
|
||||||
leftIcon={
|
|
||||||
<Icon
|
|
||||||
name="check-circle"
|
|
||||||
css={{ color: '$green11', fontSize: '$xl', mr: '$2' }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
||||||
<Text css={{ fontSize: '$sm', color: '$slate11' }}>
|
<Text css={{ fontSize: '$sm', color: '$slate11' }}>
|
||||||
|
|
@ -42,6 +27,6 @@ export const CreateAccessPointSuccess: React.FC = () => {
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</S.Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './create-ap-success';
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
import { Flex, Text } from '@/components';
|
||||||
import { styled } from '@/theme';
|
import { styled } from '@/theme';
|
||||||
|
|
||||||
import { Flex } from '../../../components/layout';
|
|
||||||
|
|
||||||
export const DisplayTextStyles = {
|
export const DisplayTextStyles = {
|
||||||
Container: styled(Flex, {
|
Container: styled(Flex, {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
|
@ -13,7 +12,7 @@ export const DisplayTextStyles = {
|
||||||
fontSize: '$xs',
|
fontSize: '$xs',
|
||||||
//TODO add variants
|
//TODO add variants
|
||||||
}),
|
}),
|
||||||
Input: styled('span', {
|
Input: styled(Text, {
|
||||||
backgroundColor: '$slate1',
|
backgroundColor: '$slate1',
|
||||||
borderColor: '$slate1',
|
borderColor: '$slate1',
|
||||||
color: '$slate12',
|
color: '$slate12',
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export const DisplayText: React.FC<DisplayTextProps> = ({
|
||||||
return (
|
return (
|
||||||
<S.Container>
|
<S.Container>
|
||||||
<S.Label>{label}</S.Label>
|
<S.Label>{label}</S.Label>
|
||||||
<S.Input>{value}</S.Input>
|
<S.Input ellipsis>{value}</S.Input>
|
||||||
</S.Container>
|
</S.Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
import { useQuery } from '@apollo/client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Combobox, InputGroup, InputGroupText } from '@/components';
|
import { Combobox, InputGroup, InputGroupText } from '@/components';
|
||||||
|
import { totalTokensDocument } from '@/graphclient';
|
||||||
import { useDebounce } from '@/hooks';
|
import { useDebounce } from '@/hooks';
|
||||||
|
import { FleekERC721 } from '@/integrations/ethereum/contracts';
|
||||||
import { AppLog } from '@/utils';
|
import { AppLog } from '@/utils';
|
||||||
|
|
||||||
import { Explore } from '../explore.context';
|
import { Explore } from '../explore.context';
|
||||||
|
|
@ -21,6 +24,7 @@ const orderResults: SortItem[] = [
|
||||||
|
|
||||||
export const NFASearchFragment: React.FC = () => {
|
export const NFASearchFragment: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
|
search,
|
||||||
setEndReached,
|
setEndReached,
|
||||||
setOrderBy,
|
setOrderBy,
|
||||||
setOrderDirection,
|
setOrderDirection,
|
||||||
|
|
@ -29,6 +33,13 @@ export const NFASearchFragment: React.FC = () => {
|
||||||
} = Explore.useContext();
|
} = Explore.useContext();
|
||||||
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
const [selectedValue, setSelectedValue] = useState<SortItem>(orderResults[0]);
|
||||||
|
|
||||||
|
const { data: totalTokens } = useQuery(totalTokensDocument, {
|
||||||
|
variables: {
|
||||||
|
contractId: FleekERC721.address,
|
||||||
|
},
|
||||||
|
skip: Boolean(search),
|
||||||
|
});
|
||||||
|
|
||||||
const handleSortChange = (item: SortItem | undefined): void => {
|
const handleSortChange = (item: SortItem | undefined): void => {
|
||||||
if (item) {
|
if (item) {
|
||||||
setSelectedValue(item);
|
setSelectedValue(item);
|
||||||
|
|
@ -72,8 +83,10 @@ export const NFASearchFragment: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<S.Container>
|
<S.Container>
|
||||||
<S.Data.Wrapper>
|
<S.Data.Wrapper>
|
||||||
<S.Data.Text>All NFAs </S.Data.Text>
|
{totalTokens?.collection && (<>
|
||||||
<S.Data.Number>(3,271)</S.Data.Number>
|
<S.Data.Text>All NFAs </S.Data.Text>
|
||||||
|
<S.Data.Number>({totalTokens.collection.totalTokens})</S.Data.Number>
|
||||||
|
</>)}
|
||||||
</S.Data.Wrapper>
|
</S.Data.Wrapper>
|
||||||
|
|
||||||
<S.Input.Wrapper>
|
<S.Input.Wrapper>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import { Card, Grid, Stepper } from '@/components';
|
import {
|
||||||
import { MintCardHeader } from '@/views/mint/mint-card';
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
Stepper,
|
||||||
|
} from '@/components';
|
||||||
|
|
||||||
import { GithubButton } from './github-button';
|
import { GithubButton } from './github-button';
|
||||||
|
|
||||||
|
|
@ -7,10 +12,10 @@ export const GithubConnect: React.FC = () => {
|
||||||
const { prevStep } = Stepper.useContext();
|
const { prevStep } = Stepper.useContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<MintCardHeader title="Connect GitHub" onClickBack={prevStep} />
|
<CustomCardHeader.Default title="Connect GitHub" onClickBack={prevStep} />
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Grid css={{ rowGap: '$6' }}>
|
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||||
<GithubButton />
|
<GithubButton />
|
||||||
<Card.Text
|
<Card.Text
|
||||||
css={{
|
css={{
|
||||||
|
|
@ -24,8 +29,8 @@ export const GithubConnect: React.FC = () => {
|
||||||
After connecting your GitHub, your repositories will show here.
|
After connecting your GitHub, your repositories will show here.
|
||||||
</span>
|
</span>
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
</Grid>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { CustomCardHeader } from '@/components';
|
||||||
import { Mint } from '@/views/mint/mint.context';
|
import { Mint } from '@/views/mint/mint.context';
|
||||||
import { MintCardHeader } from '@/views/mint/mint-card';
|
|
||||||
import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
|
import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
|
||||||
|
|
||||||
export const RepoConfigurationHeader: React.FC = () => {
|
export const RepoConfigurationHeader: React.FC = () => {
|
||||||
|
|
@ -22,7 +22,7 @@ export const RepoConfigurationHeader: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MintCardHeader
|
<CustomCardHeader.Default
|
||||||
title="Configure Repository"
|
title="Configure Repository"
|
||||||
onClickBack={handlePrevStepClick}
|
onClickBack={handlePrevStepClick}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { Card } from '@/components';
|
import { CustomCardContainer } from '@/components';
|
||||||
|
|
||||||
import { RepoConfigurationBody } from './repo-configuration-body';
|
import { RepoConfigurationBody } from './repo-configuration-body';
|
||||||
import { RepoConfigurationHeader } from './repo-configuration-header';
|
import { RepoConfigurationHeader } from './repo-configuration-header';
|
||||||
|
|
||||||
export const GithubRepoConfiguration: React.FC = () => {
|
export const GithubRepoConfiguration: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ minWidth: '17rem', maxWidth: '$107h' }}>
|
<CustomCardContainer css={{ minWidth: '17rem' }}>
|
||||||
<RepoConfigurationHeader />
|
<RepoConfigurationHeader />
|
||||||
<RepoConfigurationBody />
|
<RepoConfigurationBody />
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,21 @@
|
||||||
import { Card, Flex, Icon } from '@/components';
|
import {
|
||||||
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
Icon,
|
||||||
|
} from '@/components';
|
||||||
import { styled } from '@/theme';
|
import { styled } from '@/theme';
|
||||||
|
|
||||||
export const GithubRepositorySelectionStyles = {
|
export const GithubRepositorySelectionStyles = {
|
||||||
Card: {
|
Card: {
|
||||||
Wrapper: styled(Card.Container, {
|
Wrapper: styled(CustomCardContainer, {
|
||||||
maxWidth: '$107h',
|
|
||||||
maxHeight: '$95h',
|
maxHeight: '$95h',
|
||||||
pr: '$3h',
|
pr: '$3h',
|
||||||
}),
|
}),
|
||||||
|
Header: styled(CustomCardHeader.Default, {
|
||||||
|
pr: '$3h',
|
||||||
|
}),
|
||||||
Body: styled(Card.Body, {
|
Body: styled(Card.Body, {
|
||||||
pt: '$4',
|
pt: '$4',
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import {
|
import { Flex, InputGroup, InputGroupText, Spinner } from '@/components';
|
||||||
Card,
|
|
||||||
Flex,
|
|
||||||
Icon,
|
|
||||||
IconButton,
|
|
||||||
InputGroup,
|
|
||||||
InputGroupText,
|
|
||||||
Spinner,
|
|
||||||
} from '@/components';
|
|
||||||
import { useDebounce } from '@/hooks/use-debounce';
|
import { useDebounce } from '@/hooks/use-debounce';
|
||||||
import { useGithubStore } from '@/store';
|
import { useGithubStore } from '@/store';
|
||||||
import { Mint } from '@/views/mint/mint.context';
|
import { Mint } from '@/views/mint/mint.context';
|
||||||
|
|
@ -55,27 +47,9 @@ export const GithubRepositoryConnection: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<S.Card.Wrapper>
|
<S.Card.Wrapper>
|
||||||
<Card.Heading
|
<S.Card.Header
|
||||||
title="Select Repository"
|
title="Select Repository"
|
||||||
css={{ pr: '$3h' }}
|
onClickBack={handlePrevStepClick}
|
||||||
leftIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="back"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="back" />}
|
|
||||||
css={{ mr: '$2' }}
|
|
||||||
onClick={handlePrevStepClick}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="info"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<S.Card.Body>
|
<S.Card.Body>
|
||||||
<S.Container>
|
<S.Container>
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export * from './mint-card';
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { Card, Icon, IconButton } from '@/components';
|
|
||||||
|
|
||||||
type MintCardHeaderProps = {
|
|
||||||
title: string;
|
|
||||||
onClickBack: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MintCardHeader: React.FC<MintCardHeaderProps> = ({
|
|
||||||
title,
|
|
||||||
onClickBack,
|
|
||||||
}: MintCardHeaderProps) => {
|
|
||||||
return (
|
|
||||||
<Card.Heading
|
|
||||||
title={title}
|
|
||||||
leftIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="back" />}
|
|
||||||
css={{ mr: '$2' }}
|
|
||||||
onClick={onClickBack}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -12,6 +12,7 @@ export const MintStepper: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
transaction: { isSuccess },
|
transaction: { isSuccess },
|
||||||
} = Mint.useTransactionContext();
|
} = Mint.useTransactionContext();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
form: {
|
form: {
|
||||||
isValid: [, setIsValid],
|
isValid: [, setIsValid],
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,14 @@ export const MintStyles = {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
|
||||||
'@media (min-width: 1024px)': {
|
'@md': {
|
||||||
|
//to align on center
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
},
|
||||||
|
|
||||||
|
'@lg': {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
import { useAccount } from 'wagmi';
|
import { useAccount } from 'wagmi';
|
||||||
|
|
||||||
import { Button, Card, Grid, Stepper } from '@/components';
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
Stepper,
|
||||||
|
} from '@/components';
|
||||||
import { AppLog } from '@/utils';
|
import { AppLog } from '@/utils';
|
||||||
import { parseColorToNumber } from '@/utils/color';
|
import { parseColorToNumber } from '@/utils/color';
|
||||||
|
|
||||||
import { Mint } from '../../mint.context';
|
import { Mint } from '../../mint.context';
|
||||||
import { MintCardHeader } from '../../mint-card';
|
|
||||||
import {
|
import {
|
||||||
AppDescriptionField,
|
AppDescriptionField,
|
||||||
AppNameField,
|
AppNameField,
|
||||||
|
|
@ -78,20 +84,24 @@ export const MintFormStep: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<MintCardHeader title="NFA Details" onClickBack={handlePrevStep} />
|
<CustomCardHeader.Default
|
||||||
|
title="NFA Details"
|
||||||
|
onClickBack={handlePrevStep}
|
||||||
|
/>
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Grid
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
rowGap: '$6',
|
gap: '$6',
|
||||||
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Grid css={{ rowGap: '$4' }}>
|
<Flex css={{ gap: '$4', flexDirection: 'column' }}>
|
||||||
<AppNameField />
|
<AppNameField />
|
||||||
<AppDescriptionField />
|
<AppDescriptionField />
|
||||||
<EnsDomainField />
|
<EnsDomainField />
|
||||||
<LogoField />
|
<LogoField />
|
||||||
</Grid>
|
</Flex>
|
||||||
<Button
|
<Button
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
|
|
@ -100,8 +110,8 @@ export const MintFormStep: React.FC = () => {
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { useQuery } from '@apollo/client';
|
||||||
|
import { useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { getVerifiersDocument } from '@/../.graphclient';
|
||||||
|
import { Form, ResolvedAddress } from '@/components';
|
||||||
|
import { useENSStore } from '@/store';
|
||||||
|
|
||||||
|
import { useMintFormContext } from '../form-step';
|
||||||
|
|
||||||
|
// TODO: remove mocked items after graphql api is fixed
|
||||||
|
const mockedItems = [
|
||||||
|
'0xdBb04e00D5ec8C9e3aeF811D315Ee7C147c5DBFD',
|
||||||
|
'0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SelectVerifier: React.FC = () => {
|
||||||
|
const {
|
||||||
|
form: { verifier },
|
||||||
|
} = useMintFormContext();
|
||||||
|
|
||||||
|
const {
|
||||||
|
value: [selectedVerifier, setSelectedVerifier],
|
||||||
|
} = verifier;
|
||||||
|
|
||||||
|
const { addressMap } = useENSStore();
|
||||||
|
|
||||||
|
const { data } = useQuery(getVerifiersDocument);
|
||||||
|
|
||||||
|
const items = useMemo(() => {
|
||||||
|
if (!data) return [];
|
||||||
|
|
||||||
|
const verifiers = data.verifiers
|
||||||
|
.map<string>((verifier) => verifier.id.toString())
|
||||||
|
.concat(mockedItems);
|
||||||
|
|
||||||
|
return verifiers.map((verifier) => ({
|
||||||
|
address: verifier,
|
||||||
|
ens: addressMap[verifier]?.value,
|
||||||
|
}));
|
||||||
|
}, [data, addressMap]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedVerifier && items.length > 0) {
|
||||||
|
setSelectedVerifier(items[0].address);
|
||||||
|
}
|
||||||
|
}, [selectedVerifier, setSelectedVerifier, items]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Field context={verifier}>
|
||||||
|
<Form.Combobox
|
||||||
|
items={items}
|
||||||
|
handleValue={(item) => item.address}
|
||||||
|
queryKey={['address', 'ens']}
|
||||||
|
>
|
||||||
|
{({ Field, Options }) => (
|
||||||
|
<>
|
||||||
|
<Field>
|
||||||
|
{(selected) =>
|
||||||
|
selected ? (
|
||||||
|
<ResolvedAddress>{selected.address}</ResolvedAddress>
|
||||||
|
) : (
|
||||||
|
'Select a Verifier'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Field>
|
||||||
|
<Options>
|
||||||
|
{(item) => <ResolvedAddress>{item.address}</ResolvedAddress>}
|
||||||
|
</Options>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form.Combobox>
|
||||||
|
</Form.Field>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Card, Flex, Text } from '@/components';
|
||||||
|
import { styled } from '@/theme';
|
||||||
|
|
||||||
|
export const VerifyNfaStepStyles = {
|
||||||
|
Body: {
|
||||||
|
Container: styled(Flex, {
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '$6',
|
||||||
|
}),
|
||||||
|
Text: styled(Text, {
|
||||||
|
color: '$slate11',
|
||||||
|
fontSize: '$sm',
|
||||||
|
}),
|
||||||
|
VerifyContainer: styled(Card.Text, {
|
||||||
|
p: '$4',
|
||||||
|
textAlign: 'left',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
borderRadius: '$lg',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -1,88 +1,17 @@
|
||||||
import { useQuery } from '@apollo/client';
|
|
||||||
import { useEffect, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { getVerifiersDocument } from '@/../.graphclient';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Flex,
|
CustomCardContainer,
|
||||||
Form,
|
CustomCardHeader,
|
||||||
ResolvedAddress,
|
|
||||||
Stepper,
|
Stepper,
|
||||||
Switch,
|
Switch,
|
||||||
Text,
|
Text,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useENSStore } from '@/store';
|
|
||||||
|
|
||||||
import { Mint } from '../../mint.context';
|
import { Mint } from '../../mint.context';
|
||||||
import { MintCardHeader } from '../../mint-card';
|
|
||||||
import { useMintFormContext } from '../form-step';
|
import { useMintFormContext } from '../form-step';
|
||||||
|
import { SelectVerifier } from './select-verifier';
|
||||||
// TODO: remove mocked items after graphql api is fixed
|
import { VerifyNfaStepStyles as S } from './verify-nfa-step.styles';
|
||||||
const mockedItems = [
|
|
||||||
'0xdBb04e00D5ec8C9e3aeF811D315Ee7C147c5DBFD',
|
|
||||||
'0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049',
|
|
||||||
];
|
|
||||||
|
|
||||||
const SelectVerifier: React.FC = () => {
|
|
||||||
const {
|
|
||||||
form: { verifier },
|
|
||||||
} = useMintFormContext();
|
|
||||||
|
|
||||||
const {
|
|
||||||
value: [selectedVerifier, setSelectedVerifier],
|
|
||||||
} = verifier;
|
|
||||||
|
|
||||||
const { addressMap } = useENSStore();
|
|
||||||
|
|
||||||
const { data } = useQuery(getVerifiersDocument);
|
|
||||||
|
|
||||||
const items = useMemo(() => {
|
|
||||||
if (!data) return [];
|
|
||||||
|
|
||||||
const verifiers = data.verifiers
|
|
||||||
.map<string>((verifier) => verifier.id.toString())
|
|
||||||
.concat(mockedItems);
|
|
||||||
|
|
||||||
return verifiers.map((verifier) => ({
|
|
||||||
address: verifier,
|
|
||||||
ens: addressMap[verifier]?.value,
|
|
||||||
}));
|
|
||||||
}, [data, addressMap]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!selectedVerifier && items.length > 0) {
|
|
||||||
setSelectedVerifier(items[0].address);
|
|
||||||
}
|
|
||||||
}, [selectedVerifier, setSelectedVerifier, items]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form.Field context={verifier}>
|
|
||||||
<Form.Combobox
|
|
||||||
items={items}
|
|
||||||
handleValue={(item) => item.address}
|
|
||||||
queryKey={['address', 'ens']}
|
|
||||||
>
|
|
||||||
{({ Field, Options }) => (
|
|
||||||
<>
|
|
||||||
<Field>
|
|
||||||
{(selected) =>
|
|
||||||
selected ? (
|
|
||||||
<ResolvedAddress>{selected.address}</ResolvedAddress>
|
|
||||||
) : (
|
|
||||||
'Select a Verifier'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Field>
|
|
||||||
<Options>
|
|
||||||
{(item) => <ResolvedAddress>{item.address}</ResolvedAddress>}
|
|
||||||
</Options>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Form.Combobox>
|
|
||||||
</Form.Field>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const VerifyNFAStep: React.FC = () => {
|
export const VerifyNFAStep: React.FC = () => {
|
||||||
const { prevStep } = Stepper.useContext();
|
const { prevStep } = Stepper.useContext();
|
||||||
|
|
@ -100,30 +29,22 @@ export const VerifyNFAStep: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<MintCardHeader title="Verify NFA" onClickBack={prevStep} />
|
<CustomCardHeader.Default title="Verify NFA" onClickBack={prevStep} />
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
<S.Body.Container>
|
||||||
<Text css={{ color: '$slate11', fontSize: '$sm' }}>
|
<S.Body.Text>
|
||||||
Below you can allow Fleek to be added as a controller to your NFA.
|
Below you can allow Fleek to be added as a controller to your NFA.
|
||||||
This will allow Fleek to automatically verify your NFA and update
|
This will allow Fleek to automatically verify your NFA and update
|
||||||
builds and other metadata. It will not allow Fleek to transfer or
|
builds and other metadata. It will not allow Fleek to transfer or
|
||||||
burn your NFT. You can change this setting later on your NFA but
|
burn your NFT. You can change this setting later on your NFA but
|
||||||
adding it now will save you a transaction in the future. We
|
adding it now will save you a transaction in the future. We
|
||||||
recommend it so that your users can get verified NFAs.
|
recommend it so that your users can get verified NFAs.
|
||||||
</Text>
|
</S.Body.Text>
|
||||||
<Card.Text
|
<S.Body.VerifyContainer>
|
||||||
css={{
|
|
||||||
p: '$4',
|
|
||||||
textAlign: 'left',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
borderRadius: '$lg',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text css={{ color: '$slate12' }}>Verify NFA</Text>
|
<Text css={{ color: '$slate12' }}>Verify NFA</Text>
|
||||||
<Switch checked={verifyNFA} onChange={setVerifyNFA} />
|
<Switch checked={verifyNFA} onChange={setVerifyNFA} />
|
||||||
</Card.Text>
|
</S.Body.VerifyContainer>
|
||||||
<SelectVerifier />
|
<SelectVerifier />
|
||||||
<Button
|
<Button
|
||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
|
|
@ -133,8 +54,8 @@ export const VerifyNFAStep: React.FC = () => {
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</S.Body.Container>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
import { Button, Card, Grid } from '@/components';
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
Text,
|
||||||
|
} from '@/components';
|
||||||
import { NFAPreview } from '@/components';
|
import { NFAPreview } from '@/components';
|
||||||
|
|
||||||
import { useMintFormContext } from '../nfa-step/form-step';
|
import { useMintFormContext } from '../nfa-step/form-step';
|
||||||
|
|
@ -16,8 +23,6 @@ type NftCardProps = {
|
||||||
|
|
||||||
export const NftCard: React.FC<NftCardProps> = ({
|
export const NftCard: React.FC<NftCardProps> = ({
|
||||||
title,
|
title,
|
||||||
leftIcon,
|
|
||||||
rightIcon,
|
|
||||||
message,
|
message,
|
||||||
buttonText,
|
buttonText,
|
||||||
leftIconButton,
|
leftIconButton,
|
||||||
|
|
@ -43,23 +48,21 @@ export const NftCard: React.FC<NftCardProps> = ({
|
||||||
} = useMintFormContext();
|
} = useMintFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h', p: '$0' }}>
|
<CustomCardContainer css={{ p: '$0' }}>
|
||||||
<NFAPreview
|
<NFAPreview
|
||||||
color={logoColor}
|
color={logoColor}
|
||||||
logo={appLogo}
|
logo={appLogo}
|
||||||
name={appName}
|
name={appName}
|
||||||
ens={ens}
|
ens={ens}
|
||||||
size={size}
|
size={size}
|
||||||
className="rounded-t-xhl"
|
css={{
|
||||||
|
bt: '1.25rem',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Card.Body css={{ p: '$7' }}>
|
<Card.Body css={{ p: '$7' }}>
|
||||||
<Grid css={{ rowGap: '$6' }}>
|
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||||
<Card.Heading
|
<CustomCardHeader.Success title={title} />
|
||||||
title={title}
|
<Text css={{ color: '$slate11', fontSize: '$sm' }}>{message}</Text>
|
||||||
leftIcon={leftIcon}
|
|
||||||
rightIcon={rightIcon}
|
|
||||||
/>
|
|
||||||
<span className="text-slate11 text-sm">{message}</span>
|
|
||||||
<Button
|
<Button
|
||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
|
|
@ -70,8 +73,8 @@ export const NftCard: React.FC<NftCardProps> = ({
|
||||||
>
|
>
|
||||||
{buttonText}
|
{buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { ConnectKitButton } from 'connectkit';
|
import { ConnectKitButton } from 'connectkit';
|
||||||
|
|
||||||
import { Button, Stepper } from '@/components';
|
import { Stepper } from '@/components';
|
||||||
|
|
||||||
import { ButtonConnection } from '../button-connection';
|
import { ButtonConnection } from '../button-connection';
|
||||||
|
|
||||||
|
|
@ -9,19 +9,14 @@ export const ConnectWalletButton: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConnectKitButton.Custom>
|
<ConnectKitButton.Custom>
|
||||||
{({ isConnected, show, truncatedAddress, address }) => {
|
{({ isConnected, show, address }) => {
|
||||||
if (isConnected && address) {
|
if (isConnected && address) {
|
||||||
return (
|
nextStep();
|
||||||
<Button onClick={nextStep} css={{ color: '$slate12' }}>
|
|
||||||
{truncatedAddress}. Continue
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<ButtonConnection
|
<ButtonConnection
|
||||||
icon={'ethereum'}
|
icon={'ethereum'}
|
||||||
label={' Connect Wallet'}
|
label={'Connect Wallet'}
|
||||||
disabled={isConnected}
|
|
||||||
onClick={show}
|
onClick={show}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,18 @@
|
||||||
import { Card, Grid, Icon, IconButton } from '@/components';
|
import {
|
||||||
|
Card,
|
||||||
|
CustomCardContainer,
|
||||||
|
CustomCardHeader,
|
||||||
|
Flex,
|
||||||
|
} from '@/components';
|
||||||
|
|
||||||
import { ConnectWalletButton } from './connect-wallet-button';
|
import { ConnectWalletButton } from './connect-wallet-button';
|
||||||
|
|
||||||
export const WalletStep: React.FC = () => {
|
export const WalletStep: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
<CustomCardContainer>
|
||||||
<Card.Heading
|
<CustomCardHeader.Default title="Connect Wallet" />
|
||||||
title="Connect Wallet"
|
|
||||||
rightIcon={
|
|
||||||
<IconButton
|
|
||||||
aria-label="Add"
|
|
||||||
colorScheme="gray"
|
|
||||||
variant="link"
|
|
||||||
icon={<Icon name="info" />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Grid css={{ rowGap: '$6' }}>
|
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||||
<ConnectWalletButton />
|
<ConnectWalletButton />
|
||||||
<Card.Text
|
<Card.Text
|
||||||
css={{
|
css={{
|
||||||
|
|
@ -29,8 +24,8 @@ export const WalletStep: React.FC = () => {
|
||||||
>
|
>
|
||||||
<span>Connect with the wallet you want to mint & own the NFA.</span>
|
<span>Connect with the wallet you want to mint & own the NFA.</span>
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
</Grid>
|
</Flex>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card.Container>
|
</CustomCardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue