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 commitHash,
|
||||
string gitRepository,
|
||||
string ipfsHash,
|
||||
string logo,
|
||||
uint24 color,
|
||||
bool accessPointAutoApproval,
|
||||
|
|
@ -108,6 +109,7 @@ contract FleekERC721 is
|
|||
string calldata ens,
|
||||
string memory commitHash,
|
||||
string memory gitRepository,
|
||||
string memory ipfsHash,
|
||||
string memory logo,
|
||||
uint24 color,
|
||||
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.
|
||||
app.currentBuild = 0;
|
||||
app.builds[0] = Build(commitHash, gitRepository);
|
||||
app.builds[0] = Build(commitHash, gitRepository, ipfsHash, externalURL);
|
||||
|
||||
emit NewMint(
|
||||
tokenId,
|
||||
|
|
@ -141,6 +143,7 @@ contract FleekERC721 is
|
|||
ens,
|
||||
commitHash,
|
||||
gitRepository,
|
||||
ipfsHash,
|
||||
logo,
|
||||
color,
|
||||
accessPointAutoApproval,
|
||||
|
|
@ -396,11 +399,14 @@ contract FleekERC721 is
|
|||
function setTokenBuild(
|
||||
uint256 tokenId,
|
||||
string memory _commitHash,
|
||||
string memory _gitRepository
|
||||
string memory _gitRepository,
|
||||
string memory _ipfsHash,
|
||||
string memory _domain
|
||||
) public virtual requireTokenRole(tokenId, TokenRoles.Controller) {
|
||||
_requireMinted(tokenId);
|
||||
_apps[tokenId].builds[++_apps[tokenId].currentBuild] = Build(_commitHash, _gitRepository);
|
||||
emit MetadataUpdate(tokenId, "build", [_commitHash, _gitRepository], msg.sender);
|
||||
_apps[tokenId].builds[++_apps[tokenId].currentBuild] = Build(_commitHash, _gitRepository, _ipfsHash, _domain);
|
||||
// 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, 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);
|
||||
|
||||
/**
|
||||
|
|
@ -33,6 +33,8 @@ interface IERCX {
|
|||
struct Build {
|
||||
string commitHash;
|
||||
string gitRepository;
|
||||
string ipfsHash;
|
||||
string domain;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,7 +86,13 @@ interface IERCX {
|
|||
/**
|
||||
* @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.
|
||||
|
|
|
|||
|
|
@ -369,29 +369,31 @@ contract Test_FleekERC721_AccessControl is Test_FleekERC721_Base, Test_FleekERC7
|
|||
function test_setTokenBuild() public {
|
||||
string memory commitHash = "commitHash";
|
||||
string memory gitRepository = "gitRepository";
|
||||
string memory ipfsHash = "ipfsHash";
|
||||
string memory domain = "domain";
|
||||
|
||||
// ColletionOwner
|
||||
vm.prank(collectionOwner);
|
||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||
|
||||
// CollectionVerifier
|
||||
vm.prank(collectionVerifier);
|
||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||
|
||||
// TokenOwner
|
||||
vm.prank(tokenOwner);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||
|
||||
// TokenController
|
||||
vm.prank(tokenController);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||
|
||||
// AnyAddress
|
||||
vm.prank(anyAddress);
|
||||
expectRevertWithTokenRole(tokenId, FleekAccessControl.TokenRoles.Controller);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository);
|
||||
CuT.setTokenBuild(tokenId, commitHash, gitRepository, ipfsHash, domain);
|
||||
}
|
||||
|
||||
function test_burn() public {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ contract Test_FleekERC721_Billing is Test_FleekERC721_Base, Test_FleekERC721_Bil
|
|||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
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_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
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_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
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_IPFS_HASH = "mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a";
|
||||
|
||||
uint24 public constant APP_COLOR = 0x123456;
|
||||
|
||||
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 newCommitHash,
|
||||
string memory newRepository,
|
||||
string memory newIpfsHash,
|
||||
string memory newDomain,
|
||||
string memory newLogo,
|
||||
uint24 newColor
|
||||
) public {
|
||||
|
|
@ -47,7 +49,7 @@ contract Test_FleekERC721_GetToken is Test_FleekERC721_Base {
|
|||
CuT.setTokenExternalURL(tokenId, newExternalURL);
|
||||
transferENS(newENS, deployer);
|
||||
CuT.setTokenENS(tokenId, newENS);
|
||||
CuT.setTokenBuild(tokenId, newCommitHash, newRepository);
|
||||
CuT.setTokenBuild(tokenId, newCommitHash, newRepository, newIpfsHash, newDomain);
|
||||
CuT.setTokenLogoAndColor(tokenId, newLogo, newColor);
|
||||
|
||||
(
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
"fleek.eth",
|
||||
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
||||
"https://github.com/a-different/repository",
|
||||
"mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a",
|
||||
TestConstants.LOGO_1,
|
||||
0x654321,
|
||||
false,
|
||||
|
|
@ -56,6 +57,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
"fleek.eth",
|
||||
"94e8ba38568aea4fb277a37a4c472d94a6ce880a",
|
||||
"https://github.com/a-different/repository",
|
||||
"mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a",
|
||||
TestConstants.LOGO_1,
|
||||
0x654321,
|
||||
true,
|
||||
|
|
@ -81,6 +83,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
string memory ens,
|
||||
string memory commitHash,
|
||||
string memory gitRepository,
|
||||
string memory ipfsHash,
|
||||
string memory logo,
|
||||
uint24 color,
|
||||
bool autoApprovalAp
|
||||
|
|
@ -95,6 +98,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
ens,
|
||||
commitHash,
|
||||
gitRepository,
|
||||
ipfsHash,
|
||||
logo,
|
||||
color,
|
||||
autoApprovalAp,
|
||||
|
|
@ -115,6 +119,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
false,
|
||||
|
|
@ -131,6 +136,7 @@ contract Test_FleekERC721_Mint is Test_FleekERC721_Base {
|
|||
"",
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ abstract contract Test_FleekERC721_Base is Test, Test_FleekERC721_Assertions {
|
|||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.APP_IPFS_HASH,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
false, // Auto Approval Is OFF
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import "./TestBase.sol";
|
|||
|
||||
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[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);
|
||||
|
||||
function expectMetadataUpdate(
|
||||
|
|
@ -22,7 +22,7 @@ contract Test_FleekERC721_TokenURIAssertions is Test {
|
|||
function expectMetadataUpdate(
|
||||
uint256 _tokenId,
|
||||
string memory key,
|
||||
string[2] memory value,
|
||||
string[4] memory value,
|
||||
address triggeredBy
|
||||
) public {
|
||||
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");
|
||||
transferENS("new-ens.eth", deployer);
|
||||
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.setTokenVerified(tokenId, true);
|
||||
|
||||
|
|
@ -96,10 +102,16 @@ contract Test_FleekERC721_TokenURI is Test_FleekERC721_Base, Test_FleekERC721_To
|
|||
expectMetadataUpdate(
|
||||
tokenId,
|
||||
"build",
|
||||
["ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo"],
|
||||
["ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo", "ipfshash", "domain"],
|
||||
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);
|
||||
CuT.setTokenLogo(tokenId, TestConstants.LOGO_1);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ describe('FleekERC721.Billing', () => {
|
|||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ describe('FleekERC721.CollectionRoles', () => {
|
|||
TestConstants.MintParams.ens,
|
||||
TestConstants.MintParams.commitHash,
|
||||
TestConstants.MintParams.gitRepository,
|
||||
TestConstants.MintParams.ipfsHash,
|
||||
TestConstants.MintParams.logo,
|
||||
TestConstants.MintParams.color,
|
||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ describe('FleekERC721.ENS', () => {
|
|||
'app.eth',
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
@ -43,6 +44,7 @@ describe('FleekERC721.ENS', () => {
|
|||
'app.eth',
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ describe('FleekERC721.GetLastTokenId', () => {
|
|||
TestConstants.MintParams.ens,
|
||||
TestConstants.MintParams.commitHash,
|
||||
TestConstants.MintParams.gitRepository,
|
||||
TestConstants.MintParams.ipfsHash,
|
||||
TestConstants.MintParams.logo,
|
||||
TestConstants.MintParams.color,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export const TestConstants = Object.freeze({
|
|||
externalUrl: 'https://fleek.co',
|
||||
commitHash: 'b72e47171746b6a9e29b801af9cb655ecf4d665c',
|
||||
gitRepository: 'https://github.com/fleekxyz/non-fungible-apps',
|
||||
ipfsHash: 'mtwirsqawjuoloq2gvtyug2tc3jbf5htm2zeo4rsknfiv3fdp46a',
|
||||
logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI1MDAiIHdpZHRoPSIyMTgzIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjQgMTQxLjUzMTk5OTk5OTk5OTk4Ij48cGF0aCBkPSJNMTAuMzgzIDEyNi44OTRMMCAwbDEyNCAuMjU1LTEwLjk3OSAxMjYuNjM5LTUwLjU1MyAxNC42Mzh6IiBmaWxsPSIjZTM0ZjI2Ii8+PHBhdGggZD0iTTYyLjQ2OCAxMjkuMjc3VjEyLjA4NWw1MS4wNjQuMTctOS4xMDYgMTA0Ljg1MXoiIGZpbGw9IiNlZjY1MmEiLz48cGF0aCBkPSJNOTkuNDkgNDEuMzYybDEuNDQ2LTE1LjQ5SDIyLjM4M2w0LjM0IDQ3LjQ5aDU0LjIxM0w3OC44MSA5My42MTdsLTE3LjM2MiA0LjY4LTE3LjYxNy01LjEwNi0uOTM2LTEyLjA4NUgyNy4zMTlsMi4xMjggMjQuNjgxIDMyIDguOTM2IDMyLjI1NS04LjkzNiA0LjM0LTQ4LjE3SDQxLjEwN0wzOS40OSA0MS4zNjJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+',
|
||||
color: 0xe34f26,
|
||||
accessPointAutoApprovalSettings: false,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ export const Events = Object.freeze({
|
|||
MetadataUpdate: {
|
||||
string: 'MetadataUpdate(uint256,string,string,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.commitHash,
|
||||
TestConstants.MintParams.gitRepository,
|
||||
TestConstants.MintParams.ipfsHash,
|
||||
TestConstants.MintParams.logo,
|
||||
TestConstants.MintParams.color,
|
||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ describe('FleekERC721.Minting', () => {
|
|||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
@ -40,6 +41,7 @@ describe('FleekERC721.Minting', () => {
|
|||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
@ -66,6 +68,7 @@ describe('FleekERC721.Minting', () => {
|
|||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
@ -87,6 +90,7 @@ describe('FleekERC721.Minting', () => {
|
|||
'',
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ describe('FleekERC721.Pausable', () => {
|
|||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.ipfsHash,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -51,12 +51,20 @@ describe('FleekERC721.UpdateProperties', () => {
|
|||
it('should emit event for build change', async () => {
|
||||
const { contract, tokenId, owner } = fixture;
|
||||
|
||||
await expect(contract.setTokenBuild(tokenId, 'commitHash', 'gitRepository'))
|
||||
.to.emit(contract, Events.MetadataUpdate.stringTuple)
|
||||
await expect(
|
||||
contract.setTokenBuild(
|
||||
tokenId,
|
||||
'commitHash',
|
||||
'gitRepository',
|
||||
'ipfsHash',
|
||||
'domain'
|
||||
)
|
||||
)
|
||||
.to.emit(contract, Events.MetadataUpdate.stringArray4)
|
||||
.withArgs(
|
||||
tokenId,
|
||||
'build',
|
||||
['commitHash', 'gitRepository'],
|
||||
['commitHash', 'gitRepository', 'ipfsHash', 'domain'],
|
||||
owner.address
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ describe('Deploy', () => {
|
|||
TestConstants.MintParams.ens,
|
||||
TestConstants.MintParams.commitHash,
|
||||
TestConstants.MintParams.gitRepository,
|
||||
TestConstants.MintParams.ipfsHash,
|
||||
TestConstants.MintParams.logo,
|
||||
TestConstants.MintParams.color,
|
||||
TestConstants.MintParams.accessPointAutoApprovalSettings,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
"pinst": "^3.0.0",
|
||||
"prettier": "^2.8.4",
|
||||
"prettier-plugin-solidity": "^1.0.0",
|
||||
"serverless-offline": "^12.0.4",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,22 @@ To deploy to development environment:
|
|||
To deploy to production environment:
|
||||
`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
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"build": "yarn tsc",
|
||||
"invoke:build": "yarn build && serverless invoke local --function submitBuildInfo",
|
||||
"prisma:generate": "npx prisma generate",
|
||||
"prisma:pull": "npx prisma db pull"
|
||||
"prisma:pull": "npx prisma db pull --force",
|
||||
"start": "serverless offline"
|
||||
},
|
||||
"author": "fleek",
|
||||
"license": "MIT",
|
||||
|
|
@ -30,12 +31,13 @@
|
|||
"@middy/http-json-body-parser": "^4.2.7",
|
||||
"@middy/http-response-serializer": "^4.2.8",
|
||||
"@prisma/client": "^4.13.0",
|
||||
"aws-sdk": "^2.1342.0",
|
||||
"prisma": "^4.13.0",
|
||||
"uuid": "^9.0.0",
|
||||
"@types/node": "^18.15.11",
|
||||
"aws-sdk": "^2.1342.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"prisma": "^4.13.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.4",
|
||||
"uuid": "^9.0.0",
|
||||
"web3": "^1.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,21 @@ datasource db {
|
|||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model tokens {
|
||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||
commit_hash String
|
||||
github_url String
|
||||
owner String
|
||||
tokenId Int
|
||||
model builds {
|
||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||
commitHash String
|
||||
domain String
|
||||
githubRepository String
|
||||
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 { formatJSONResponse } from '@libs/api-gateway';
|
||||
const querystring = require('querystring');
|
||||
|
||||
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 (
|
||||
event: APIGatewayEvent
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
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 buildInfo = {
|
||||
buildId: id,
|
||||
createdAt: new Date().toISOString(),
|
||||
submittedData: eventData,
|
||||
githubRepository: data.githubRepository,
|
||||
commitHash: data.commitHash,
|
||||
ipfsHash: data.ipfsHash,
|
||||
domain: data.domain,
|
||||
};
|
||||
|
||||
// place holder call
|
||||
nfaContract.methods
|
||||
.setTokenBuild(1, 'hash', 'repo')
|
||||
.call((err: string | undefined, res: any) => {
|
||||
if (err) throw new Error(err);
|
||||
console.log('result');
|
||||
console.log(res);
|
||||
// Add build record to the database, if it's not already added
|
||||
const buildRecord = await prisma.builds.findMany({
|
||||
where: {
|
||||
commitHash: buildInfo.commitHash,
|
||||
githubRepository: buildInfo.githubRepository,
|
||||
ipfsHash: buildInfo.ipfsHash,
|
||||
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({
|
||||
buildInfo,
|
||||
|
|
|
|||
|
|
@ -6,31 +6,185 @@ import {
|
|||
import { formatJSONResponse } from '@libs/api-gateway';
|
||||
|
||||
import { v4 } from 'uuid';
|
||||
import { initPrisma, prisma } from '@libs/prisma';
|
||||
import { account, nfaContract, web3 } from '@libs/nfa-contract';
|
||||
|
||||
export const submitMintInfo = async (
|
||||
event: APIGatewayEvent
|
||||
///context: APIGatewayEventRequestContext
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
try {
|
||||
if (event.body === null) {
|
||||
return formatJSONResponse({
|
||||
status: 422,
|
||||
message: 'Required parameters were not passed.',
|
||||
});
|
||||
}
|
||||
const id = v4();
|
||||
|
||||
/**if (!verifyAlchemySig(event.headers.xalchemywork)) {
|
||||
throw new Error('Invalid sig');
|
||||
}**/
|
||||
|
||||
if (event.body == undefined) {
|
||||
throw new Error('Undefined data');
|
||||
}
|
||||
const eventBody = JSON.parse(event.body);
|
||||
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 = {
|
||||
buildId: id,
|
||||
mintId: id,
|
||||
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
|
||||
// if so, trigger verification call
|
||||
// if not, add to mongo
|
||||
initPrisma();
|
||||
|
||||
// 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({
|
||||
mintInfo,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,18 @@
|
|||
import Web3 from 'web3';
|
||||
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 abi = abiFile.abi as any;
|
||||
|
||||
const web3 = new Web3('https://rpc.goerli.mudit.blog');
|
||||
export const abi = abiFile.abi as any;
|
||||
|
||||
export const web3 = new Web3('https://rpc.goerli.mudit.blog');
|
||||
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()
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(() => {
|
||||
prisma.$disconnect();
|
||||
});
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
"outDir": "dist",
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
|
|
|
|||
|
|
@ -1588,7 +1588,7 @@
|
|||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz"
|
||||
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
||||
|
||||
"@types/node@*", "@types/node@^18.15.5":
|
||||
"@types/node@*":
|
||||
version "18.15.5"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz"
|
||||
integrity sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==
|
||||
|
|
@ -1598,6 +1598,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
|
||||
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":
|
||||
version "3.1.0"
|
||||
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:
|
||||
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==
|
||||
|
||||
duration@^0.2.2:
|
||||
|
|
@ -6262,10 +6267,10 @@ typedarray-to-buffer@^3.1.5:
|
|||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz"
|
||||
integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==
|
||||
typescript@^5.0.4:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
||||
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
||||
|
||||
ultron@~1.1.0:
|
||||
version "1.1.1"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ type NewMint @entity(immutable: true) {
|
|||
ENS: String!
|
||||
commitHash: String! # string
|
||||
gitRepository: String! # string
|
||||
ipfsHash: String!
|
||||
logo: String!
|
||||
color: Int!
|
||||
accessPointAutoApproval: Boolean!
|
||||
|
|
@ -44,7 +45,7 @@ type MetadataUpdate @entity(immutable: true) {
|
|||
key: String!
|
||||
stringValue: String
|
||||
uint24Value: Int
|
||||
doubleStringValue: [String!]!
|
||||
multipleStringValue: [String!]!
|
||||
booleanValue: Boolean
|
||||
byAddress: Bytes!
|
||||
blockNumber: BigInt!
|
||||
|
|
@ -76,12 +77,20 @@ type Token @entity {
|
|||
owner: Owner!
|
||||
mintedBy: Bytes!
|
||||
controllers: [Controller!]
|
||||
gitRepository: GitRepository!
|
||||
commitHash: String!
|
||||
accessPoints: [AccessPoint!] @derivedFrom(field: "token")
|
||||
verifier: Verifier # Address
|
||||
verified: Boolean!
|
||||
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
|
||||
|
|
@ -106,7 +115,7 @@ type Verifier @entity {
|
|||
|
||||
type GitRepository @entity {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
GitRepository as GitRepositoryEntity,
|
||||
MetadataUpdate,
|
||||
Token,
|
||||
Build,
|
||||
} from '../generated/schema';
|
||||
|
||||
export function handleMetadataUpdateWithStringValue(
|
||||
|
|
@ -61,7 +62,7 @@ export function handleMetadataUpdateWithStringValue(
|
|||
}
|
||||
}
|
||||
|
||||
export function handleMetadataUpdateWithDoubleStringValue(
|
||||
export function handleMetadataUpdateWithMultipleStringValues(
|
||||
event: MetadataUpdateEvent3
|
||||
): void {
|
||||
/**
|
||||
|
|
@ -73,30 +74,29 @@ export function handleMetadataUpdateWithDoubleStringValue(
|
|||
|
||||
entity.key = event.params.key;
|
||||
entity.tokenId = event.params._tokenId;
|
||||
entity.doubleStringValue = event.params.value;
|
||||
entity.multipleStringValue = event.params.value;
|
||||
entity.blockNumber = event.block.number;
|
||||
entity.blockTimestamp = event.block.timestamp;
|
||||
entity.transactionHash = event.transaction.hash;
|
||||
|
||||
entity.save();
|
||||
|
||||
// UPDATE TOKEN
|
||||
const token = Token.load(
|
||||
// CREATE BUILD
|
||||
const build = new Build(
|
||||
Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId))
|
||||
);
|
||||
|
||||
if (token) {
|
||||
if (event.params.key == 'build') {
|
||||
let gitRepositoryEntity = GitRepositoryEntity.load(event.params.value[1]);
|
||||
if (!gitRepositoryEntity) {
|
||||
// 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();
|
||||
if (event.params.key == 'build') {
|
||||
let gitRepositoryEntity = GitRepositoryEntity.load(event.params.value[1]);
|
||||
if (!gitRepositoryEntity) {
|
||||
// Create a new gitRepository entity
|
||||
gitRepositoryEntity = new GitRepositoryEntity(event.params.value[1]);
|
||||
}
|
||||
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 ENS = event.params.ENS;
|
||||
const gitRepository = event.params.gitRepository;
|
||||
const ipfsHash = event.params.ipfsHash;
|
||||
const commitHash = event.params.commitHash;
|
||||
const logo = event.params.logo;
|
||||
const color = event.params.color;
|
||||
|
|
@ -38,6 +39,7 @@ export function handleNewMint(event: NewMintEvent): void {
|
|||
newMintEntity.ENS = ENS;
|
||||
newMintEntity.commitHash = commitHash;
|
||||
newMintEntity.gitRepository = gitRepository;
|
||||
newMintEntity.ipfsHash = ipfsHash;
|
||||
newMintEntity.logo = logo;
|
||||
newMintEntity.color = color;
|
||||
newMintEntity.accessPointAutoApproval = accessPointAutoApproval;
|
||||
|
|
@ -68,8 +70,6 @@ export function handleNewMint(event: NewMintEvent): void {
|
|||
token.description = description;
|
||||
token.externalURL = externalURL;
|
||||
token.ENS = ENS;
|
||||
token.gitRepository = gitRepository;
|
||||
token.commitHash = commitHash;
|
||||
token.logo = logo;
|
||||
token.color = color;
|
||||
token.accessPointAutoApproval = accessPointAutoApproval;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ dataSources:
|
|||
- ChangeAccessPointAutoApproval
|
||||
abis:
|
||||
- name: FleekNFA
|
||||
file: ../contracts/deployments/goerli/FleekERC721.json
|
||||
file: ../contracts/artifacts/contracts/FleekERC721.sol/FleekERC721.json
|
||||
eventHandlers:
|
||||
- event: Approval(indexed address,indexed address,indexed uint256)
|
||||
handler: handleApproval
|
||||
|
|
@ -41,13 +41,13 @@ dataSources:
|
|||
# Token Events
|
||||
- event: MetadataUpdate(indexed uint256,string,string,indexed address)
|
||||
handler: handleMetadataUpdateWithStringValue
|
||||
- event: MetadataUpdate(indexed uint256,string,string[2],indexed address)
|
||||
handler: handleMetadataUpdateWithDoubleStringValue
|
||||
- event: MetadataUpdate(indexed uint256,string,string[4],indexed address)
|
||||
handler: handleMetadataUpdateWithMultipleStringValues
|
||||
- event: MetadataUpdate(indexed uint256,string,uint24,indexed address)
|
||||
handler: handleMetadataUpdateWithIntValue
|
||||
- event: MetadataUpdate(indexed uint256,string,bool,indexed address)
|
||||
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
|
||||
- event: Transfer(indexed address,indexed address,indexed uint256)
|
||||
handler: handleTransfer
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ query lastNFAsPaginated(
|
|||
}
|
||||
}
|
||||
|
||||
query totalTokens($contractId: ID!) {
|
||||
collection(id: $contractId) {
|
||||
totalTokens
|
||||
}
|
||||
}
|
||||
|
||||
query getNFADetail($id: ID!) {
|
||||
token(id: $id) {
|
||||
accessPoints {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"scripts": {
|
||||
"dev": "vite",
|
||||
"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",
|
||||
"preview": "vite preview",
|
||||
"prod": "yarn build && npx serve dist -s"
|
||||
|
|
|
|||
|
|
@ -11,10 +11,8 @@ export abstract class CardStyles {
|
|||
borderWidth: '$default',
|
||||
});
|
||||
|
||||
static readonly Heading = styled('h3', {
|
||||
color: '$slate12',
|
||||
fontSize: '$xl',
|
||||
fontWeight: '$medium',
|
||||
static readonly Header = styled('div', {
|
||||
width: '$full',
|
||||
});
|
||||
|
||||
static readonly Body = styled('div', {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import React, { forwardRef } from 'react';
|
||||
|
||||
import { Flex } from '../layout';
|
||||
import { CardStyles } from './card.styles';
|
||||
|
||||
export abstract class Card {
|
||||
|
|
@ -15,21 +14,7 @@ export abstract class Card {
|
|||
}
|
||||
);
|
||||
|
||||
static readonly Heading = forwardRef<HTMLHeadingElement, Card.HeadingProps>(
|
||||
({ 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 Header = CardStyles.Header;
|
||||
|
||||
static readonly Body = forwardRef<HTMLDivElement, Card.BodyProps>(
|
||||
({ children, ...props }, ref) => {
|
||||
|
|
@ -57,12 +42,7 @@ export namespace Card {
|
|||
typeof CardStyles.Container
|
||||
>;
|
||||
|
||||
export type HeadingProps = {
|
||||
title: string;
|
||||
css?: React.CSSProperties;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
} & React.ComponentProps<typeof CardStyles.Heading>;
|
||||
export type HeadingProps = React.ComponentProps<typeof CardStyles.Header>;
|
||||
|
||||
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 './custom-card';
|
||||
|
|
|
|||
|
|
@ -126,17 +126,6 @@ const getButtonCompoundVariant = ({
|
|||
'&:focus, &:active': {
|
||||
backgroundColor: `$${color}3`,
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
backgroundColor: `initial`,
|
||||
'&:hover': {
|
||||
color: `$${color}11`,
|
||||
backgroundColor: `initial`,
|
||||
},
|
||||
'& img, & svg': {
|
||||
filter: 'grayscale(100%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,11 @@ export abstract class PageStyles {
|
|||
width: '100%',
|
||||
minHeight: '85vh',
|
||||
maxWidth: '$6xl',
|
||||
padding: '0 $6',
|
||||
padding: '$6',
|
||||
margin: '0 auto',
|
||||
display: 'grid',
|
||||
|
||||
'@md': {
|
||||
padding: '0 $6',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Text } from '@/components';
|
||||
import { keyframes, styled } from '@/theme';
|
||||
|
||||
const Loading = keyframes({
|
||||
|
|
@ -13,7 +14,7 @@ const Loading = keyframes({
|
|||
});
|
||||
|
||||
export const ResolvedAddressStyles = {
|
||||
Container: styled('span', {
|
||||
Container: styled(Text, {
|
||||
'&[data-loading="true"]': {
|
||||
animation: `${Loading} 1s ease-in-out infinite`,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export const media = {
|
||||
// Breakpoints
|
||||
xs: '(min-width: 375px)',
|
||||
sm: '(min-width: 640px)',
|
||||
md: '(min-width: 768px)',
|
||||
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';
|
||||
|
||||
|
|
@ -6,28 +12,8 @@ export const CreateAccessPointForm: React.FC = () => {
|
|||
const { prevStep } = Stepper.useContext();
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<Card.Heading
|
||||
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" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default title="Enter Domain" onClickBack={prevStep} />
|
||||
<Card.Body>
|
||||
<Flex
|
||||
css={{
|
||||
|
|
@ -38,6 +24,6 @@ export const CreateAccessPointForm: React.FC = () => {
|
|||
<CreateAccessPointFormBody />
|
||||
</Flex>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
</CustomCardContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
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 { useAccessPointFormContext } from '../ap-form-step';
|
||||
|
|
@ -49,9 +49,10 @@ export const APRecordCardBody: React.FC = () => {
|
|||
</Text>
|
||||
</Card.Text>
|
||||
) : (
|
||||
<Grid
|
||||
<Flex
|
||||
css={{
|
||||
rowGap: '$6',
|
||||
gap: '$6',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Text>
|
||||
|
|
@ -73,7 +74,7 @@ export const APRecordCardBody: React.FC = () => {
|
|||
>
|
||||
I added the record
|
||||
</Button>
|
||||
</Grid>
|
||||
</Flex>
|
||||
)}
|
||||
</Card.Body>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,29 +1,9 @@
|
|||
import { Card, Icon, IconButton, Stepper } from '@/components';
|
||||
import { CustomCardHeader, Stepper } from '@/components';
|
||||
|
||||
export const APRecordCardHeader: React.FC = () => {
|
||||
const { prevStep } = Stepper.useContext();
|
||||
|
||||
return (
|
||||
<Card.Heading
|
||||
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" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<CustomCardHeader.Default title="Create Record" onClickBack={prevStep} />
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { Card } from '@/components';
|
||||
import { CustomCardContainer } from '@/components';
|
||||
|
||||
import { APRecordCardBody } from './ap-record-body';
|
||||
import { APRecordCardHeader } from './ap-record-header';
|
||||
|
||||
export const APRecordStep: React.FC = () => {
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<CustomCardContainer>
|
||||
<APRecordCardHeader />
|
||||
<APRecordCardBody />
|
||||
</Card.Container>
|
||||
</CustomCardContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import { useAccount } from 'wagmi';
|
|||
import {
|
||||
Button,
|
||||
Card,
|
||||
CustomCardContainer,
|
||||
CustomCardHeader,
|
||||
Flex,
|
||||
Icon,
|
||||
IconButton,
|
||||
ResolvedAddress,
|
||||
Stepper,
|
||||
Text,
|
||||
|
|
@ -40,7 +40,9 @@ export const AccessPointDataFragment: React.FC = () => {
|
|||
label="Owner"
|
||||
value={
|
||||
address ? (
|
||||
<ResolvedAddress truncated={false}>{address || ''}</ResolvedAddress>
|
||||
<ResolvedAddress truncated={false} ellipsis>
|
||||
{address}
|
||||
</ResolvedAddress>
|
||||
) : (
|
||||
'Please connect to wallet'
|
||||
)
|
||||
|
|
@ -111,28 +113,8 @@ export const CreateAccessPointPreview: React.FC = () => {
|
|||
}, [writeStatus, transactionStatus]);
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<Card.Heading
|
||||
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" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default title="Review Details" onClickBack={prevStep} />
|
||||
<Card.Body>
|
||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
||||
<AccessPointDataFragment />
|
||||
|
|
@ -148,6 +130,6 @@ export const CreateAccessPointPreview: React.FC = () => {
|
|||
</Button>
|
||||
</Flex>
|
||||
</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 { AccessPointDataFragment } from './create-ap-preview';
|
||||
import { CreateAccessPoint } from '../create-ap.context';
|
||||
import { AccessPointDataFragment } from '../create-ap-preview';
|
||||
import { CreateApSuccessStyles as S } from './create-ap-success.styles';
|
||||
|
||||
export const CreateAccessPointSuccess: React.FC = () => {
|
||||
const { nfa } = CreateAccessPoint.useContext();
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<Card.Heading
|
||||
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" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<S.Container>
|
||||
<CustomCardHeader.Success title="Hosting Successful" />
|
||||
<Card.Body>
|
||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
||||
<Text css={{ fontSize: '$sm', color: '$slate11' }}>
|
||||
|
|
@ -42,6 +27,6 @@ export const CreateAccessPointSuccess: React.FC = () => {
|
|||
</Flex>
|
||||
</Flex>
|
||||
</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 { Flex } from '../../../components/layout';
|
||||
|
||||
export const DisplayTextStyles = {
|
||||
Container: styled(Flex, {
|
||||
flexDirection: 'column',
|
||||
|
|
@ -13,7 +12,7 @@ export const DisplayTextStyles = {
|
|||
fontSize: '$xs',
|
||||
//TODO add variants
|
||||
}),
|
||||
Input: styled('span', {
|
||||
Input: styled(Text, {
|
||||
backgroundColor: '$slate1',
|
||||
borderColor: '$slate1',
|
||||
color: '$slate12',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const DisplayText: React.FC<DisplayTextProps> = ({
|
|||
return (
|
||||
<S.Container>
|
||||
<S.Label>{label}</S.Label>
|
||||
<S.Input>{value}</S.Input>
|
||||
<S.Input ellipsis>{value}</S.Input>
|
||||
</S.Container>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Combobox, InputGroup, InputGroupText } from '@/components';
|
||||
import { totalTokensDocument } from '@/graphclient';
|
||||
import { useDebounce } from '@/hooks';
|
||||
import { FleekERC721 } from '@/integrations/ethereum/contracts';
|
||||
import { AppLog } from '@/utils';
|
||||
|
||||
import { Explore } from '../explore.context';
|
||||
|
|
@ -21,6 +24,7 @@ const orderResults: SortItem[] = [
|
|||
|
||||
export const NFASearchFragment: React.FC = () => {
|
||||
const {
|
||||
search,
|
||||
setEndReached,
|
||||
setOrderBy,
|
||||
setOrderDirection,
|
||||
|
|
@ -29,6 +33,13 @@ export const NFASearchFragment: React.FC = () => {
|
|||
} = Explore.useContext();
|
||||
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 => {
|
||||
if (item) {
|
||||
setSelectedValue(item);
|
||||
|
|
@ -72,8 +83,10 @@ export const NFASearchFragment: React.FC = () => {
|
|||
return (
|
||||
<S.Container>
|
||||
<S.Data.Wrapper>
|
||||
<S.Data.Text>All NFAs </S.Data.Text>
|
||||
<S.Data.Number>(3,271)</S.Data.Number>
|
||||
{totalTokens?.collection && (<>
|
||||
<S.Data.Text>All NFAs </S.Data.Text>
|
||||
<S.Data.Number>({totalTokens.collection.totalTokens})</S.Data.Number>
|
||||
</>)}
|
||||
</S.Data.Wrapper>
|
||||
|
||||
<S.Input.Wrapper>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { Card, Grid, Stepper } from '@/components';
|
||||
import { MintCardHeader } from '@/views/mint/mint-card';
|
||||
import {
|
||||
Card,
|
||||
CustomCardContainer,
|
||||
CustomCardHeader,
|
||||
Flex,
|
||||
Stepper,
|
||||
} from '@/components';
|
||||
|
||||
import { GithubButton } from './github-button';
|
||||
|
||||
|
|
@ -7,10 +12,10 @@ export const GithubConnect: React.FC = () => {
|
|||
const { prevStep } = Stepper.useContext();
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<MintCardHeader title="Connect GitHub" onClickBack={prevStep} />
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default title="Connect GitHub" onClickBack={prevStep} />
|
||||
<Card.Body>
|
||||
<Grid css={{ rowGap: '$6' }}>
|
||||
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||
<GithubButton />
|
||||
<Card.Text
|
||||
css={{
|
||||
|
|
@ -24,8 +29,8 @@ export const GithubConnect: React.FC = () => {
|
|||
After connecting your GitHub, your repositories will show here.
|
||||
</span>
|
||||
</Card.Text>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
</CustomCardContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CustomCardHeader } from '@/components';
|
||||
import { Mint } from '@/views/mint/mint.context';
|
||||
import { MintCardHeader } from '@/views/mint/mint-card';
|
||||
import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
|
||||
|
||||
export const RepoConfigurationHeader: React.FC = () => {
|
||||
|
|
@ -22,7 +22,7 @@ export const RepoConfigurationHeader: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<MintCardHeader
|
||||
<CustomCardHeader.Default
|
||||
title="Configure Repository"
|
||||
onClickBack={handlePrevStepClick}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { Card } from '@/components';
|
||||
import { CustomCardContainer } from '@/components';
|
||||
|
||||
import { RepoConfigurationBody } from './repo-configuration-body';
|
||||
import { RepoConfigurationHeader } from './repo-configuration-header';
|
||||
|
||||
export const GithubRepoConfiguration: React.FC = () => {
|
||||
return (
|
||||
<Card.Container css={{ minWidth: '17rem', maxWidth: '$107h' }}>
|
||||
<CustomCardContainer css={{ minWidth: '17rem' }}>
|
||||
<RepoConfigurationHeader />
|
||||
<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';
|
||||
|
||||
export const GithubRepositorySelectionStyles = {
|
||||
Card: {
|
||||
Wrapper: styled(Card.Container, {
|
||||
maxWidth: '$107h',
|
||||
Wrapper: styled(CustomCardContainer, {
|
||||
maxHeight: '$95h',
|
||||
pr: '$3h',
|
||||
}),
|
||||
Header: styled(CustomCardHeader.Default, {
|
||||
pr: '$3h',
|
||||
}),
|
||||
Body: styled(Card.Body, {
|
||||
pt: '$4',
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import {
|
||||
Card,
|
||||
Flex,
|
||||
Icon,
|
||||
IconButton,
|
||||
InputGroup,
|
||||
InputGroupText,
|
||||
Spinner,
|
||||
} from '@/components';
|
||||
import { Flex, InputGroup, InputGroupText, Spinner } from '@/components';
|
||||
import { useDebounce } from '@/hooks/use-debounce';
|
||||
import { useGithubStore } from '@/store';
|
||||
import { Mint } from '@/views/mint/mint.context';
|
||||
|
|
@ -55,27 +47,9 @@ export const GithubRepositoryConnection: React.FC = () => {
|
|||
|
||||
return (
|
||||
<S.Card.Wrapper>
|
||||
<Card.Heading
|
||||
<S.Card.Header
|
||||
title="Select Repository"
|
||||
css={{ pr: '$3h' }}
|
||||
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" />}
|
||||
/>
|
||||
}
|
||||
onClickBack={handlePrevStepClick}
|
||||
/>
|
||||
<S.Card.Body>
|
||||
<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 {
|
||||
transaction: { isSuccess },
|
||||
} = Mint.useTransactionContext();
|
||||
|
||||
const {
|
||||
form: {
|
||||
isValid: [, setIsValid],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,14 @@ export const MintStyles = {
|
|||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
|
||||
'@media (min-width: 1024px)': {
|
||||
'@md': {
|
||||
//to align on center
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
},
|
||||
|
||||
'@lg': {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
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 { parseColorToNumber } from '@/utils/color';
|
||||
|
||||
import { Mint } from '../../mint.context';
|
||||
import { MintCardHeader } from '../../mint-card';
|
||||
import {
|
||||
AppDescriptionField,
|
||||
AppNameField,
|
||||
|
|
@ -78,20 +84,24 @@ export const MintFormStep: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<MintCardHeader title="NFA Details" onClickBack={handlePrevStep} />
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default
|
||||
title="NFA Details"
|
||||
onClickBack={handlePrevStep}
|
||||
/>
|
||||
<Card.Body>
|
||||
<Grid
|
||||
<Flex
|
||||
css={{
|
||||
rowGap: '$6',
|
||||
gap: '$6',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Grid css={{ rowGap: '$4' }}>
|
||||
<Flex css={{ gap: '$4', flexDirection: 'column' }}>
|
||||
<AppNameField />
|
||||
<AppDescriptionField />
|
||||
<EnsDomainField />
|
||||
<LogoField />
|
||||
</Grid>
|
||||
</Flex>
|
||||
<Button
|
||||
disabled={!isValid}
|
||||
colorScheme="blue"
|
||||
|
|
@ -100,8 +110,8 @@ export const MintFormStep: React.FC = () => {
|
|||
>
|
||||
Continue
|
||||
</Button>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</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 {
|
||||
Button,
|
||||
Card,
|
||||
Flex,
|
||||
Form,
|
||||
ResolvedAddress,
|
||||
CustomCardContainer,
|
||||
CustomCardHeader,
|
||||
Stepper,
|
||||
Switch,
|
||||
Text,
|
||||
} from '@/components';
|
||||
import { useENSStore } from '@/store';
|
||||
|
||||
import { Mint } from '../../mint.context';
|
||||
import { MintCardHeader } from '../../mint-card';
|
||||
import { useMintFormContext } from '../form-step';
|
||||
|
||||
// TODO: remove mocked items after graphql api is fixed
|
||||
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>
|
||||
);
|
||||
};
|
||||
import { SelectVerifier } from './select-verifier';
|
||||
import { VerifyNfaStepStyles as S } from './verify-nfa-step.styles';
|
||||
|
||||
export const VerifyNFAStep: React.FC = () => {
|
||||
const { prevStep } = Stepper.useContext();
|
||||
|
|
@ -100,30 +29,22 @@ export const VerifyNFAStep: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<MintCardHeader title="Verify NFA" onClickBack={prevStep} />
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default title="Verify NFA" onClickBack={prevStep} />
|
||||
<Card.Body>
|
||||
<Flex css={{ flexDirection: 'column', gap: '$6' }}>
|
||||
<Text css={{ color: '$slate11', fontSize: '$sm' }}>
|
||||
<S.Body.Container>
|
||||
<S.Body.Text>
|
||||
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
|
||||
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
|
||||
adding it now will save you a transaction in the future. We
|
||||
recommend it so that your users can get verified NFAs.
|
||||
</Text>
|
||||
<Card.Text
|
||||
css={{
|
||||
p: '$4',
|
||||
textAlign: 'left',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
borderRadius: '$lg',
|
||||
}}
|
||||
>
|
||||
</S.Body.Text>
|
||||
<S.Body.VerifyContainer>
|
||||
<Text css={{ color: '$slate12' }}>Verify NFA</Text>
|
||||
<Switch checked={verifyNFA} onChange={setVerifyNFA} />
|
||||
</Card.Text>
|
||||
</S.Body.VerifyContainer>
|
||||
<SelectVerifier />
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
|
|
@ -133,8 +54,8 @@ export const VerifyNFAStep: React.FC = () => {
|
|||
>
|
||||
Continue
|
||||
</Button>
|
||||
</Flex>
|
||||
</S.Body.Container>
|
||||
</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 { useMintFormContext } from '../nfa-step/form-step';
|
||||
|
|
@ -16,8 +23,6 @@ type NftCardProps = {
|
|||
|
||||
export const NftCard: React.FC<NftCardProps> = ({
|
||||
title,
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
message,
|
||||
buttonText,
|
||||
leftIconButton,
|
||||
|
|
@ -43,23 +48,21 @@ export const NftCard: React.FC<NftCardProps> = ({
|
|||
} = useMintFormContext();
|
||||
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h', p: '$0' }}>
|
||||
<CustomCardContainer css={{ p: '$0' }}>
|
||||
<NFAPreview
|
||||
color={logoColor}
|
||||
logo={appLogo}
|
||||
name={appName}
|
||||
ens={ens}
|
||||
size={size}
|
||||
className="rounded-t-xhl"
|
||||
css={{
|
||||
bt: '1.25rem',
|
||||
}}
|
||||
/>
|
||||
<Card.Body css={{ p: '$7' }}>
|
||||
<Grid css={{ rowGap: '$6' }}>
|
||||
<Card.Heading
|
||||
title={title}
|
||||
leftIcon={leftIcon}
|
||||
rightIcon={rightIcon}
|
||||
/>
|
||||
<span className="text-slate11 text-sm">{message}</span>
|
||||
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||
<CustomCardHeader.Success title={title} />
|
||||
<Text css={{ color: '$slate11', fontSize: '$sm' }}>{message}</Text>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
|
|
@ -70,8 +73,8 @@ export const NftCard: React.FC<NftCardProps> = ({
|
|||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
</CustomCardContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ConnectKitButton } from 'connectkit';
|
||||
|
||||
import { Button, Stepper } from '@/components';
|
||||
import { Stepper } from '@/components';
|
||||
|
||||
import { ButtonConnection } from '../button-connection';
|
||||
|
||||
|
|
@ -9,19 +9,14 @@ export const ConnectWalletButton: React.FC = () => {
|
|||
|
||||
return (
|
||||
<ConnectKitButton.Custom>
|
||||
{({ isConnected, show, truncatedAddress, address }) => {
|
||||
{({ isConnected, show, address }) => {
|
||||
if (isConnected && address) {
|
||||
return (
|
||||
<Button onClick={nextStep} css={{ color: '$slate12' }}>
|
||||
{truncatedAddress}. Continue
|
||||
</Button>
|
||||
);
|
||||
nextStep();
|
||||
} else {
|
||||
return (
|
||||
<ButtonConnection
|
||||
icon={'ethereum'}
|
||||
label={' Connect Wallet'}
|
||||
disabled={isConnected}
|
||||
label={'Connect Wallet'}
|
||||
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';
|
||||
|
||||
export const WalletStep: React.FC = () => {
|
||||
return (
|
||||
<Card.Container css={{ maxWidth: '$107h' }}>
|
||||
<Card.Heading
|
||||
title="Connect Wallet"
|
||||
rightIcon={
|
||||
<IconButton
|
||||
aria-label="Add"
|
||||
colorScheme="gray"
|
||||
variant="link"
|
||||
icon={<Icon name="info" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<CustomCardContainer>
|
||||
<CustomCardHeader.Default title="Connect Wallet" />
|
||||
<Card.Body>
|
||||
<Grid css={{ rowGap: '$6' }}>
|
||||
<Flex css={{ gap: '$6', flexDirection: 'column' }}>
|
||||
<ConnectWalletButton />
|
||||
<Card.Text
|
||||
css={{
|
||||
|
|
@ -29,8 +24,8 @@ export const WalletStep: React.FC = () => {
|
|||
>
|
||||
<span>Connect with the wallet you want to mint & own the NFA.</span>
|
||||
</Card.Text>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
</CustomCardContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue