From 615a0fdba6f94529e4fc165f94e4de0a91d7c8da Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:48:35 -0700 Subject: [PATCH 1/7] use aptogotchi holder to demonstrate indexer --- .github/workflows/move_tests.yaml | 18 ++++ .idea/.gitignore | 3 - .idea/aptogotchi.iml | 12 --- .idea/modules.xml | 8 -- .idea/vcs.xml | 6 -- frontend/.env | 2 +- frontend/src/app/home/Connected.tsx | 23 +++-- frontend/src/app/home/Pet/Collection.tsx | 109 +++++++++++++++++++++++ frontend/src/app/home/Pet/index.tsx | 3 + move/.idea/workspace.xml | 41 +++++++-- move/Move.toml | 3 + move/sh_scripts/dev_setup.sh | 25 ++++++ move/sh_scripts/move_publish.sh | 13 +++ move/sh_scripts/move_tests.sh | 9 ++ move/sources/aptogotchi.move | 58 +++++++----- 15 files changed, 272 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/move_tests.yaml delete mode 100644 .idea/.gitignore delete mode 100644 .idea/aptogotchi.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml create mode 100644 frontend/src/app/home/Pet/Collection.tsx create mode 100755 move/sh_scripts/dev_setup.sh create mode 100755 move/sh_scripts/move_publish.sh create mode 100755 move/sh_scripts/move_tests.sh diff --git a/.github/workflows/move_tests.yaml b/.github/workflows/move_tests.yaml new file mode 100644 index 00000000..efda5164 --- /dev/null +++ b/.github/workflows/move_tests.yaml @@ -0,0 +1,18 @@ +name: "Move Tests" +on: + pull_request: + push: + branches: + - main + - testnet + - mainnet + +jobs: + move-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dev dependencies. + run: ./move/sh_scripts/dev_setup.sh + - name: Runs move tests. + run: ./move/sh_scripts/move_tests.sh diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/aptogotchi.iml b/.idea/aptogotchi.iml deleted file mode 100644 index 284c98d8..00000000 --- a/.idea/aptogotchi.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 9818af79..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddf..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/.env b/frontend/.env index 4a52b9b7..d69292c8 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,4 +1,4 @@ -NEXT_PUBLIC_CONTRACT_ADDRESS="0xb59fdd48812b24195b47742306ae420a2c78b7833704e6c7f89a41d611054953" +NEXT_PUBLIC_CONTRACT_ADDRESS="0x327d9ba5d1bdc6c3e6e607add36f51c5136de9e7f2e47da497f758a1c0db0520" NEXT_PUBLIC_BODY_OPTIONS=5 NEXT_PUBLIC_EAR_OPTIONS=6 NEXT_PUBLIC_FACE_OPTIONS=4 diff --git a/frontend/src/app/home/Connected.tsx b/frontend/src/app/home/Connected.tsx index 3478a534..780dd63e 100644 --- a/frontend/src/app/home/Connected.tsx +++ b/frontend/src/app/home/Connected.tsx @@ -15,23 +15,34 @@ export function Connected() { const fetchPet = useCallback(async () => { if (!account?.address) return; - const payload = { + const getAptogotchiPayload = { function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi`, type_arguments: [], arguments: [account.address], }; - const response = await provider.view(payload); + const getAptogotchiAddressPayload = { + function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi_address`, + type_arguments: [], + arguments: [account.address], + }; + + const [aptogotchiResponse, aptogotchiAddressResponse] = await Promise.all([ + provider.view(getAptogotchiPayload), + provider.view(getAptogotchiAddressPayload), + ]); + const noPet = ["", "0", "0", "0x"]; - if (JSON.stringify(response) !== JSON.stringify(noPet)) { + if (JSON.stringify(aptogotchiResponse) !== JSON.stringify(noPet)) { setPet({ - name: response[0] as unknown as string, - energy_points: parseInt(response[2] as unknown as string), - parts: (response[3] as unknown as string) + name: aptogotchiResponse[0] as unknown as string, + energy_points: parseInt(aptogotchiResponse[2] as unknown as string), + parts: (aptogotchiResponse[3] as unknown as string) .split("0") .slice(2) .map(Number), + address: aptogotchiAddressResponse[0] as unknown as string, }); } }, [account?.address]); diff --git a/frontend/src/app/home/Pet/Collection.tsx b/frontend/src/app/home/Pet/Collection.tsx new file mode 100644 index 00000000..4adbcb36 --- /dev/null +++ b/frontend/src/app/home/Pet/Collection.tsx @@ -0,0 +1,109 @@ +"use client"; + +import { Pet } from "."; +import { useCallback, useState, useEffect } from "react"; +import { useWallet } from "@aptos-labs/wallet-adapter-react"; +import { Network, Provider } from "aptos"; + +export const provider = new Provider(Network.TESTNET); + +export interface CollectionProps { + pet: Pet; +} + +export type Collection = { + collection_id: string; + collection_name: string; + creator_address: string; + uri: string; + current_supply: any; +}; + +export function Collection({ pet }: CollectionProps) { + const { account, network } = useWallet(); + const [collection, setCollection] = useState(); + const [collectionHolders, setCollectionHolders] = useState(); + + const fetchCollection = useCallback(async () => { + if (!account?.address) return; + + const tokenDataResponse = await provider.getTokenData(pet.address, { + tokenStandard: "v2", + }); + + const collectionResponse = + tokenDataResponse?.current_token_datas_v2[0].current_collection!; + + const getAllCollectionHoldersGql = { + query: ` + query MyQuery($collection_id: String) { + current_collection_ownership_v2_view( + where: { collection_id: { _eq: $collection_id } } + ) { + owner_address + } + } + `, + variables: { + collection_id: collectionResponse.collection_id, + }, + }; + const collectionHolderResponse = await provider.indexerClient.queryIndexer( + getAllCollectionHoldersGql + ); + + console.log(JSON.stringify(tokenDataResponse, null, 2)); + console.log( + JSON.stringify( + // @ts-ignore + collectionHolderResponse.current_collection_ownership_v2_view, + null, + 2 + ) + ); + + setCollection({ + collection_id: collectionResponse.collection_id, + collection_name: collectionResponse.collection_name, + creator_address: collectionResponse.creator_address, + uri: collectionResponse.uri, + current_supply: collectionResponse.current_supply, + }); + + setCollectionHolders( + // @ts-ignore + collectionHolderResponse.current_collection_ownership_v2_view.map( + // @ts-ignore + (d) => d.owner_address + ) + ); + }, [account?.address]); + + useEffect(() => { + if (!account?.address || !network) return; + + fetchCollection(); + }, [account?.address, fetchCollection, network]); + + const collectionComponent = ( +
+ + +
    + +
+
+ ); + + return ( +
+
{collectionComponent}
+
+ ); +} diff --git a/frontend/src/app/home/Pet/index.tsx b/frontend/src/app/home/Pet/index.tsx index 556b976d..0eaef4af 100644 --- a/frontend/src/app/home/Pet/index.tsx +++ b/frontend/src/app/home/Pet/index.tsx @@ -5,11 +5,13 @@ import { Actions, PetAction } from "./Actions"; import { PetDetails } from "./Details"; import { PetImage, bodies, ears, faces } from "./Image"; import { Summary } from "./Summary"; +import { Collection } from "./Collection"; export interface Pet { name: string; energy_points: number; parts: number[]; + address: string; } interface PetProps { @@ -34,6 +36,7 @@ export function Pet({ pet, setPet }: PetProps) { avatarStyle /> +
+ + @@ -16,9 +18,38 @@ - + + + + { + "associatedIndex": 6 +} diff --git a/move/Move.toml b/move/Move.toml index ee0fea56..0d57767f 100644 --- a/move/Move.toml +++ b/move/Move.toml @@ -6,6 +6,9 @@ upgrade_policy = "compatible" [addresses] aptogotchi = '_' +[dev-addresses] +aptogotchi = "0x100" + [dependencies.AptosFramework] git = 'https://github.com/aptos-labs/aptos-core.git' rev = 'main' diff --git a/move/sh_scripts/dev_setup.sh b/move/sh_scripts/dev_setup.sh new file mode 100755 index 00000000..31a4e295 --- /dev/null +++ b/move/sh_scripts/dev_setup.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +set -e + +echo "##### Installing aptos cli dependencies #####" +sudo apt-get update +sudo apt-get install libssl-dev + +echo "##### Installing aptos cli #####" +if ! command -v aptos &>/dev/null; then + echo "aptos could not be found" + echo "installing it..." + TARGET=Ubuntu-x86_64 + VERSION=2.0.2 + wget https://github.com/aptos-labs/aptos-core/releases/download/aptos-cli-v$VERSION/aptos-cli-$VERSION-$TARGET.zip + sha=$(shasum -a 256 aptos-cli-$VERSION-$TARGET.zip | awk '{ print $1 }') + [ "$sha" != "1f0ed0d0e042ff8b48b428eaaff9f52e6ff2b246a2054740d017f514c753c6cb" ] && echo "shasum mismatch" && exit 1 + unzip aptos-cli-$VERSION-$TARGET.zip + chmod +x aptos +else + echo "aptos already installed" +fi + +echo "##### Info #####" +./aptos info diff --git a/move/sh_scripts/move_publish.sh b/move/sh_scripts/move_publish.sh new file mode 100755 index 00000000..98edbfe2 --- /dev/null +++ b/move/sh_scripts/move_publish.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +echo "##### Publishing module #####" + +PROFILE=testnet-1 +ADDR=0x$(aptos config show-profiles --profile=$PROFILE | grep 'account' | sed -n 's/.*"account": \"\(.*\)\".*/\1/p') + +aptos move publish \ + --assume-yes \ + --profile $PROFILE \ + --named-addresses aptogotchi=$ADDR diff --git a/move/sh_scripts/move_tests.sh b/move/sh_scripts/move_tests.sh new file mode 100755 index 00000000..6db93d23 --- /dev/null +++ b/move/sh_scripts/move_tests.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e + +echo "##### Running tests #####" + +aptos move test \ + --package-dir move \ + --dev diff --git a/move/sources/aptogotchi.move b/move/sources/aptogotchi.move index 38577435..79521284 100644 --- a/move/sources/aptogotchi.move +++ b/move/sources/aptogotchi.move @@ -91,7 +91,11 @@ module aptogotchi::main { } // Create an Aptogotchi token object - public entry fun create_aptogotchi(user: &signer, name: String, parts: vector) acquires CollectionCapability, MintAptogotchiEvents { + public entry fun create_aptogotchi( + user: &signer, + name: String, + parts: vector + ) acquires CollectionCapability, MintAptogotchiEvents { let uri = string::utf8(APTOGOTCHI_COLLECTION_URI); let description = string::utf8(APTOGOTCHI_COLLECTION_DESCRIPTION); let token_name = to_string(&address_of(user)); @@ -135,9 +139,10 @@ module aptogotchi::main { } // Get reference to Aptogotchi token object (CAN'T modify the reference) - fun get_aptogotchi_address(creator_addr: &address): (address) acquires CollectionCapability { + #[view] + public fun get_aptogotchi_address(creator_addr: address): (address) acquires CollectionCapability { let collection = string::utf8(APTOGOTCHI_COLLECTION_NAME); - let token_name = to_string(creator_addr); + let token_name = to_string(&creator_addr); let creator = &get_token_signer(); let token_address = token::create_token_address( &signer::address_of(creator), @@ -151,7 +156,7 @@ module aptogotchi::main { // Returns true if this address owns an Aptogotchi #[view] public fun has_aptogotchi(owner_addr: address): (bool) acquires CollectionCapability { - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let has_gotchi = exists(token_address); has_gotchi @@ -159,13 +164,15 @@ module aptogotchi::main { // Returns all fields for this Aptogotchi (if found) #[view] - public fun get_aptogotchi(owner_addr: address): (String, u64, u64, vector) acquires AptoGotchi, CollectionCapability { + public fun get_aptogotchi( + owner_addr: address + ): (String, u64, u64, vector) acquires AptoGotchi, CollectionCapability { // if this address doesn't have an Aptogotchi, throw error if (has_aptogotchi(owner_addr) == false) { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global_mut(token_address); // view function can only return primitive types. @@ -175,7 +182,7 @@ module aptogotchi::main { // Returns Aptogotchi's name #[view] public fun get_name(owner_addr: address): String acquires AptoGotchi, CollectionCapability { - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global(token_address); gotchi.name @@ -184,7 +191,7 @@ module aptogotchi::main { // Sets Aptogotchi's name public entry fun set_name(owner: signer, name: String) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(&owner); - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.name = name; @@ -197,7 +204,7 @@ module aptogotchi::main { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global(token_address); gotchi.energy_points @@ -205,7 +212,7 @@ module aptogotchi::main { public entry fun feed(owner: &signer, points: u64) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.energy_points = if (gotchi.energy_points + points > ENERGY_UPPER_BOUND) { @@ -215,12 +222,11 @@ module aptogotchi::main { }; gotchi.energy_points; - } public entry fun play(owner: &signer, points: u64) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.energy_points = if (gotchi.energy_points < points) { @@ -230,7 +236,6 @@ module aptogotchi::main { }; gotchi.energy_points; - } // Returns Aptogotchi's body parts @@ -240,7 +245,7 @@ module aptogotchi::main { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global(token_address); gotchi.parts @@ -249,7 +254,7 @@ module aptogotchi::main { // Sets Aptogotchi's body parts public entry fun set_parts(owner: &signer, parts: vector) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(&owner_addr); + let token_address = get_aptogotchi_address(owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.parts = parts; @@ -260,10 +265,11 @@ module aptogotchi::main { // Setup testing environment #[test_only] use aptos_framework::account::create_account_for_test; + #[test_only] use std::string::utf8; #[test_only] - fun setup_test(aptos: &signer, account: &signer, creator: &signer){ + fun setup_test(aptos: &signer, account: &signer, creator: &signer) { // create a fake account (only for testing purposes) create_account_for_test(signer::address_of(creator)); create_account_for_test(signer::address_of(account)); @@ -274,7 +280,11 @@ module aptogotchi::main { // Test creating an Aptogotchi #[test(aptos = @0x1, account = @aptogotchi, creator = @0x123)] - fun test_create_aptogotchi(aptos: &signer, account: &signer, creator: &signer) acquires CollectionCapability, MintAptogotchiEvents { + fun test_create_aptogotchi( + aptos: &signer, + account: &signer, + creator: &signer + ) acquires CollectionCapability, MintAptogotchiEvents { setup_test(aptos, account, creator); create_aptogotchi(creator, utf8(b"test"), vector[1, 1, 1, 1]); @@ -286,7 +296,11 @@ module aptogotchi::main { // Test getting an Aptogotchi, when user has not minted #[test(aptos = @0x1, account = @aptogotchi, creator = @0x123)] #[expected_failure(abort_code = 851969, location = aptogotchi::main)] - fun test_get_aptogotchi_without_creation(aptos: &signer, account: &signer, creator: &signer) acquires CollectionCapability, AptoGotchi { + fun test_get_aptogotchi_without_creation( + aptos: &signer, + account: &signer, + creator: &signer + ) acquires CollectionCapability, AptoGotchi { setup_test(aptos, account, creator); // get aptogotchi without creating it @@ -295,7 +309,11 @@ module aptogotchi::main { // Test getting an Aptogotchi, when user has not minted #[test(aptos = @0x1, account = @aptogotchi, creator = @0x123)] - fun test_feed_and_play(aptos: &signer, account: &signer, creator: &signer) acquires CollectionCapability, MintAptogotchiEvents, AptoGotchi { + fun test_feed_and_play( + aptos: &signer, + account: &signer, + creator: &signer + ) acquires CollectionCapability, MintAptogotchiEvents, AptoGotchi { setup_test(aptos, account, creator); create_aptogotchi(creator, utf8(b"test"), vector[1, 1, 1, 1]); @@ -307,4 +325,4 @@ module aptogotchi::main { feed(creator, 3); assert!(get_energy_points(signer::address_of(creator)) == ENERGY_UPPER_BOUND - 2, 1); } -} \ No newline at end of file +} From 5aaf2d8827a8b8243ddb59c5863b81c8091635af Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:50:54 -0700 Subject: [PATCH 2/7] nit --- move/sh_scripts/move_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/sh_scripts/move_tests.sh b/move/sh_scripts/move_tests.sh index 6db93d23..f7f7eed7 100755 --- a/move/sh_scripts/move_tests.sh +++ b/move/sh_scripts/move_tests.sh @@ -4,6 +4,6 @@ set -e echo "##### Running tests #####" -aptos move test \ +./aptos move test \ --package-dir move \ --dev From c9714890ab6809f9e39dacac2693c43dbdc18882 Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:54:04 -0700 Subject: [PATCH 3/7] nit --- move/.idea/workspace.xml | 84 ---------------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 move/.idea/workspace.xml diff --git a/move/.idea/workspace.xml b/move/.idea/workspace.xml deleted file mode 100644 index 78922bd4..00000000 --- a/move/.idea/workspace.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - { - "associatedIndex": 6 -} - - - - - - - - - - - - - 1696980369869 - - - - \ No newline at end of file From f3a4786caa476b6d2ca1578e893d9f18eaceb909 Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:02:13 -0700 Subject: [PATCH 4/7] comment dev-address --- move/Move.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/move/Move.toml b/move/Move.toml index 0d57767f..cff52758 100644 --- a/move/Move.toml +++ b/move/Move.toml @@ -6,6 +6,7 @@ upgrade_policy = "compatible" [addresses] aptogotchi = '_' +# used for testing so you don't need to manually pass in the address [dev-addresses] aptogotchi = "0x100" From 3f321fcf98df8f872f67d1bf24b447564e3a15e9 Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:39:30 -0700 Subject: [PATCH 5/7] wip --- frontend/.env | 2 +- frontend/src/app/home/Connected.tsx | 43 ++++++++--- frontend/src/app/home/Pet/Collection.tsx | 95 ++++++++++++++---------- frontend/src/app/home/Pet/index.tsx | 6 +- move/Move.toml | 2 +- move/sh_scripts/move_publish.sh | 2 +- move/sources/aptogotchi.move | 34 +++++---- 7 files changed, 113 insertions(+), 71 deletions(-) diff --git a/frontend/.env b/frontend/.env index d69292c8..25888508 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,4 +1,4 @@ -NEXT_PUBLIC_CONTRACT_ADDRESS="0x327d9ba5d1bdc6c3e6e607add36f51c5136de9e7f2e47da497f758a1c0db0520" +NEXT_PUBLIC_CONTRACT_ADDRESS="0xe7f3b4e9c597522d45cc26893cfe35f27a20e01c50c2e91ab6ed0e4831a578f1" NEXT_PUBLIC_BODY_OPTIONS=5 NEXT_PUBLIC_EAR_OPTIONS=6 NEXT_PUBLIC_FACE_OPTIONS=4 diff --git a/frontend/src/app/home/Connected.tsx b/frontend/src/app/home/Connected.tsx index 780dd63e..cc89315f 100644 --- a/frontend/src/app/home/Connected.tsx +++ b/frontend/src/app/home/Connected.tsx @@ -10,6 +10,7 @@ export const provider = new Provider(Network.TESTNET); export function Connected() { const [pet, setPet] = useState(); + const [collectionID, setCollectionID] = useState(); const { account, network } = useWallet(); const fetchPet = useCallback(async () => { @@ -21,16 +22,7 @@ export function Connected() { arguments: [account.address], }; - const getAptogotchiAddressPayload = { - function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi_address`, - type_arguments: [], - arguments: [account.address], - }; - - const [aptogotchiResponse, aptogotchiAddressResponse] = await Promise.all([ - provider.view(getAptogotchiPayload), - provider.view(getAptogotchiAddressPayload), - ]); + const aptogotchiResponse = await provider.view(getAptogotchiPayload); const noPet = ["", "0", "0", "0x"]; @@ -42,20 +34,47 @@ export function Connected() { .split("0") .slice(2) .map(Number), - address: aptogotchiAddressResponse[0] as unknown as string, }); } }, [account?.address]); + const fetchCollectionID = useCallback(async () => { + if (!account?.address) return; + + const getAptogotchiCollectionIDPayload = { + function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi_collection_id`, + type_arguments: [], + arguments: [], + }; + + const aptogotchiCollectionIDResponse = await provider.view( + getAptogotchiCollectionIDPayload + ); + + setCollectionID(aptogotchiCollectionIDResponse as unknown as string); + }, [account?.address]); + useEffect(() => { if (!account?.address || !network) return; fetchPet(); }, [account?.address, fetchPet, network]); + useEffect(() => { + if (!account?.address || !network) return; + + fetchCollectionID(); + }, [fetchCollectionID, network]); + return (
- {pet ? : } + {collectionID ? ( + pet ? ( + + ) : ( + + ) + ) : null}
); } diff --git a/frontend/src/app/home/Pet/Collection.tsx b/frontend/src/app/home/Pet/Collection.tsx index 4adbcb36..f46c3fca 100644 --- a/frontend/src/app/home/Pet/Collection.tsx +++ b/frontend/src/app/home/Pet/Collection.tsx @@ -1,6 +1,5 @@ "use client"; -import { Pet } from "."; import { useCallback, useState, useEffect } from "react"; import { useWallet } from "@aptos-labs/wallet-adapter-react"; import { Network, Provider } from "aptos"; @@ -8,7 +7,7 @@ import { Network, Provider } from "aptos"; export const provider = new Provider(Network.TESTNET); export interface CollectionProps { - pet: Pet; + collectionID: string; } export type Collection = { @@ -19,22 +18,20 @@ export type Collection = { current_supply: any; }; -export function Collection({ pet }: CollectionProps) { +export type CollectionHolder = { + owner_address: string; +}; + +export function Collection({ collectionID }: CollectionProps) { const { account, network } = useWallet(); const [collection, setCollection] = useState(); - const [collectionHolders, setCollectionHolders] = useState(); + const [collectionHolders, setCollectionHolders] = + useState(); const fetchCollection = useCallback(async () => { if (!account?.address) return; - const tokenDataResponse = await provider.getTokenData(pet.address, { - tokenStandard: "v2", - }); - - const collectionResponse = - tokenDataResponse?.current_token_datas_v2[0].current_collection!; - - const getAllCollectionHoldersGql = { + const getCollectionDataGql = { query: ` query MyQuery($collection_id: String) { current_collection_ownership_v2_view( @@ -45,38 +42,54 @@ export function Collection({ pet }: CollectionProps) { } `, variables: { - collection_id: collectionResponse.collection_id, + collection_id: collectionID, }, }; - const collectionHolderResponse = await provider.indexerClient.queryIndexer( - getAllCollectionHoldersGql - ); - console.log(JSON.stringify(tokenDataResponse, null, 2)); - console.log( - JSON.stringify( - // @ts-ignore - collectionHolderResponse.current_collection_ownership_v2_view, - null, - 2 - ) - ); + // const tokenDataResponse = await provider. - setCollection({ - collection_id: collectionResponse.collection_id, - collection_name: collectionResponse.collection_name, - creator_address: collectionResponse.creator_address, - uri: collectionResponse.uri, - current_supply: collectionResponse.current_supply, - }); - - setCollectionHolders( - // @ts-ignore - collectionHolderResponse.current_collection_ownership_v2_view.map( - // @ts-ignore - (d) => d.owner_address - ) + const collectionResponse = await provider.indexerClient.queryIndexer( + getCollectionDataGql ); + + // const getAllCollectionHoldersGql = { + // query: ` + // query MyQuery($collection_id: String) { + // current_collection_ownership_v2_view( + // where: { collection_id: { _eq: $collection_id } } + // ) { + // owner_address + // } + // } + // `, + // variables: { + // collection_id: collectionID, + // }, + // }; + // const collectionHolderResponse = await provider.indexerClient.queryIndexer( + // getAllCollectionHoldersGql + // ); + + console.log(JSON.stringify(collectionResponse, null, 2)); + // console.log( + // JSON.stringify( + // // @ts-ignore + // collectionHolderResponse, + // null, + // 2 + // ) + // ); + + // setCollection(collectionResponse); + + // setCollectionHolders( + // collectionHolderResponse + // // // @ts-ignore + // // collectionHolderResponse.current_collection_ownership_v2_view.map( + // // // @ts-ignore + // // (d) => d.owner_address + // // ) + // ); }, [account?.address]); useEffect(() => { @@ -94,7 +107,9 @@ export function Collection({ pet }: CollectionProps) {
diff --git a/frontend/src/app/home/Pet/index.tsx b/frontend/src/app/home/Pet/index.tsx index 0eaef4af..25632123 100644 --- a/frontend/src/app/home/Pet/index.tsx +++ b/frontend/src/app/home/Pet/index.tsx @@ -11,15 +11,15 @@ export interface Pet { name: string; energy_points: number; parts: number[]; - address: string; } interface PetProps { pet: Pet; setPet: Dispatch>; + collectionID: string; } -export function Pet({ pet, setPet }: PetProps) { +export function Pet({ pet, setPet, collectionID }: PetProps) { const [selectedAction, setSelectedAction] = useState("feed"); return ( @@ -36,7 +36,7 @@ export function Pet({ pet, setPet }: PetProps) { avatarStyle /> - +
(token_address); has_gotchi @@ -172,7 +180,7 @@ module aptogotchi::main { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global_mut(token_address); // view function can only return primitive types. @@ -182,7 +190,7 @@ module aptogotchi::main { // Returns Aptogotchi's name #[view] public fun get_name(owner_addr: address): String acquires AptoGotchi, CollectionCapability { - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global(token_address); gotchi.name @@ -191,7 +199,7 @@ module aptogotchi::main { // Sets Aptogotchi's name public entry fun set_name(owner: signer, name: String) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(&owner); - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.name = name; @@ -204,7 +212,7 @@ module aptogotchi::main { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global(token_address); gotchi.energy_points @@ -212,7 +220,7 @@ module aptogotchi::main { public entry fun feed(owner: &signer, points: u64) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.energy_points = if (gotchi.energy_points + points > ENERGY_UPPER_BOUND) { @@ -226,7 +234,7 @@ module aptogotchi::main { public entry fun play(owner: &signer, points: u64) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.energy_points = if (gotchi.energy_points < points) { @@ -245,7 +253,7 @@ module aptogotchi::main { assert!(false, error::unavailable(ENOT_AVAILABLE)); }; - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global(token_address); gotchi.parts @@ -254,7 +262,7 @@ module aptogotchi::main { // Sets Aptogotchi's body parts public entry fun set_parts(owner: &signer, parts: vector) acquires AptoGotchi, CollectionCapability { let owner_addr = signer::address_of(owner); - let token_address = get_aptogotchi_address(owner_addr); + let token_address = get_aptogotchi_address(&owner_addr); let gotchi = borrow_global_mut(token_address); gotchi.parts = parts; @@ -325,4 +333,4 @@ module aptogotchi::main { feed(creator, 3); assert!(get_energy_points(signer::address_of(creator)) == ENERGY_UPPER_BOUND - 2, 1); } -} +} \ No newline at end of file From 3bc2e80d73a7374019305199ef4b5683a52e7bd0 Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:25:49 -0700 Subject: [PATCH 6/7] fix gql --- frontend/src/app/home/Connected.tsx | 6 +- frontend/src/app/home/Pet/Collection.tsx | 73 ++++++++++-------------- frontend/src/utils/address.ts | 8 +++ 3 files changed, 41 insertions(+), 46 deletions(-) create mode 100644 frontend/src/utils/address.ts diff --git a/frontend/src/app/home/Connected.tsx b/frontend/src/app/home/Connected.tsx index cc89315f..d9baa53f 100644 --- a/frontend/src/app/home/Connected.tsx +++ b/frontend/src/app/home/Connected.tsx @@ -47,11 +47,11 @@ export function Connected() { arguments: [], }; - const aptogotchiCollectionIDResponse = await provider.view( + const aptogotchiCollectionIDResponse = (await provider.view( getAptogotchiCollectionIDPayload - ); + )) as string[]; - setCollectionID(aptogotchiCollectionIDResponse as unknown as string); + setCollectionID(aptogotchiCollectionIDResponse[0]); }, [account?.address]); useEffect(() => { diff --git a/frontend/src/app/home/Pet/Collection.tsx b/frontend/src/app/home/Pet/Collection.tsx index f46c3fca..2ff85766 100644 --- a/frontend/src/app/home/Pet/Collection.tsx +++ b/frontend/src/app/home/Pet/Collection.tsx @@ -3,6 +3,7 @@ import { useCallback, useState, useEffect } from "react"; import { useWallet } from "@aptos-labs/wallet-adapter-react"; import { Network, Provider } from "aptos"; +import { padAddressIfNeeded } from "@/utils/address"; export const provider = new Provider(Network.TESTNET); @@ -22,6 +23,11 @@ export type CollectionHolder = { owner_address: string; }; +export type CollectionResponse = { + current_collections_v2: Collection[]; + current_collection_ownership_v2_view: CollectionHolder[]; +}; + export function Collection({ collectionID }: CollectionProps) { const { account, network } = useWallet(); const [collection, setCollection] = useState(); @@ -34,6 +40,24 @@ export function Collection({ collectionID }: CollectionProps) { const getCollectionDataGql = { query: ` query MyQuery($collection_id: String) { + current_collections_v2( + where: { collection_id: { _eq: $collection_id } } + ) { + collection_id + collection_name + current_supply + description + creator_address + last_transaction_timestamp + max_supply + last_transaction_version + mutable_description + mutable_uri + token_standard + table_handle_v1 + total_minted_v2 + uri + } current_collection_ownership_v2_view( where: { collection_id: { _eq: $collection_id } } ) { @@ -42,54 +66,17 @@ export function Collection({ collectionID }: CollectionProps) { } `, variables: { - collection_id: collectionID, + collection_id: padAddressIfNeeded(collectionID), }, }; - // const tokenDataResponse = await provider. + const collectionResponse: CollectionResponse = + await provider.indexerClient.queryIndexer(getCollectionDataGql); - const collectionResponse = await provider.indexerClient.queryIndexer( - getCollectionDataGql + setCollection(collectionResponse.current_collections_v2[0]); + setCollectionHolders( + collectionResponse.current_collection_ownership_v2_view ); - - // const getAllCollectionHoldersGql = { - // query: ` - // query MyQuery($collection_id: String) { - // current_collection_ownership_v2_view( - // where: { collection_id: { _eq: $collection_id } } - // ) { - // owner_address - // } - // } - // `, - // variables: { - // collection_id: collectionID, - // }, - // }; - // const collectionHolderResponse = await provider.indexerClient.queryIndexer( - // getAllCollectionHoldersGql - // ); - - console.log(JSON.stringify(collectionResponse, null, 2)); - // console.log( - // JSON.stringify( - // // @ts-ignore - // collectionHolderResponse, - // null, - // 2 - // ) - // ); - - // setCollection(collectionResponse); - - // setCollectionHolders( - // collectionHolderResponse - // // // @ts-ignore - // // collectionHolderResponse.current_collection_ownership_v2_view.map( - // // // @ts-ignore - // // (d) => d.owner_address - // // ) - // ); }, [account?.address]); useEffect(() => { diff --git a/frontend/src/utils/address.ts b/frontend/src/utils/address.ts new file mode 100644 index 00000000..c9fe3d9f --- /dev/null +++ b/frontend/src/utils/address.ts @@ -0,0 +1,8 @@ +// In some case the leading char is 0 after the 0x and it got truncated +// This function will add it back if needed cause indexer doesn't auto pad it +export function padAddressIfNeeded(address: string) { + if (address.length === 67) { + return address; + } + return `0x0${address.slice(2)}`; +} From a6a2dd4564b16a8954044719edba6bd23db4e3dc Mon Sep 17 00:00:00 2001 From: 0xaptosj <129789810+0xaptosj@users.noreply.github.com> Date: Thu, 19 Oct 2023 14:36:36 -0700 Subject: [PATCH 7/7] get collection in collection component --- frontend/src/app/home/Connected.tsx | 51 ++++-------------------- frontend/src/app/home/Pet/Collection.tsx | 19 ++++++--- frontend/src/app/home/Pet/index.tsx | 5 +-- frontend/src/utils/address.ts | 6 ++- 4 files changed, 28 insertions(+), 53 deletions(-) diff --git a/frontend/src/app/home/Connected.tsx b/frontend/src/app/home/Connected.tsx index d9baa53f..97761ab2 100644 --- a/frontend/src/app/home/Connected.tsx +++ b/frontend/src/app/home/Connected.tsx @@ -10,71 +10,36 @@ export const provider = new Provider(Network.TESTNET); export function Connected() { const [pet, setPet] = useState(); - const [collectionID, setCollectionID] = useState(); const { account, network } = useWallet(); const fetchPet = useCallback(async () => { if (!account?.address) return; - const getAptogotchiPayload = { + const [name, _, energyPoints, parts] = await provider.view({ function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi`, type_arguments: [], arguments: [account.address], - }; + }); - const aptogotchiResponse = await provider.view(getAptogotchiPayload); - - const noPet = ["", "0", "0", "0x"]; - - if (JSON.stringify(aptogotchiResponse) !== JSON.stringify(noPet)) { + const noPet = { name: "", birthday: 0, energyPoints: 0, parts: "0x" }; + if (name !== noPet.name) { setPet({ - name: aptogotchiResponse[0] as unknown as string, - energy_points: parseInt(aptogotchiResponse[2] as unknown as string), - parts: (aptogotchiResponse[3] as unknown as string) - .split("0") - .slice(2) - .map(Number), + name: name as string, + energy_points: parseInt(energyPoints as string), + parts: (parts as string).split("0").slice(2).map(Number), }); } }, [account?.address]); - const fetchCollectionID = useCallback(async () => { - if (!account?.address) return; - - const getAptogotchiCollectionIDPayload = { - function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi_collection_id`, - type_arguments: [], - arguments: [], - }; - - const aptogotchiCollectionIDResponse = (await provider.view( - getAptogotchiCollectionIDPayload - )) as string[]; - - setCollectionID(aptogotchiCollectionIDResponse[0]); - }, [account?.address]); - useEffect(() => { if (!account?.address || !network) return; fetchPet(); }, [account?.address, fetchPet, network]); - useEffect(() => { - if (!account?.address || !network) return; - - fetchCollectionID(); - }, [fetchCollectionID, network]); - return (
- {collectionID ? ( - pet ? ( - - ) : ( - - ) - ) : null} + {pet ? : }
); } diff --git a/frontend/src/app/home/Pet/Collection.tsx b/frontend/src/app/home/Pet/Collection.tsx index 2ff85766..07aedb68 100644 --- a/frontend/src/app/home/Pet/Collection.tsx +++ b/frontend/src/app/home/Pet/Collection.tsx @@ -7,10 +7,6 @@ import { padAddressIfNeeded } from "@/utils/address"; export const provider = new Provider(Network.TESTNET); -export interface CollectionProps { - collectionID: string; -} - export type Collection = { collection_id: string; collection_name: string; @@ -28,7 +24,7 @@ export type CollectionResponse = { current_collection_ownership_v2_view: CollectionHolder[]; }; -export function Collection({ collectionID }: CollectionProps) { +export function Collection() { const { account, network } = useWallet(); const [collection, setCollection] = useState(); const [collectionHolders, setCollectionHolders] = @@ -37,6 +33,18 @@ export function Collection({ collectionID }: CollectionProps) { const fetchCollection = useCallback(async () => { if (!account?.address) return; + const getAptogotchiCollectionIDPayload = { + function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi_collection_id`, + type_arguments: [], + arguments: [], + }; + + const aptogotchiCollectionIDResponse = (await provider.view( + getAptogotchiCollectionIDPayload + )) as [`0x${string}`]; + + const collectionID = aptogotchiCollectionIDResponse[0]; + const getCollectionDataGql = { query: ` query MyQuery($collection_id: String) { @@ -93,6 +101,7 @@ export function Collection({ collectionID }: CollectionProps) {