Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

display all aptogotchi holders to demonstrate indexer usage #26

Merged
merged 7 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/move_tests.yaml
Original file line number Diff line number Diff line change
@@ -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
0xZihan marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 0 additions & 3 deletions .idea/.gitignore

This file was deleted.

12 changes: 0 additions & 12 deletions .idea/aptogotchi.iml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NEXT_PUBLIC_CONTRACT_ADDRESS="0xb59fdd48812b24195b47742306ae420a2c78b7833704e6c7f89a41d611054953"
NEXT_PUBLIC_CONTRACT_ADDRESS="0xe7f3b4e9c597522d45cc26893cfe35f27a20e01c50c2e91ab6ed0e4831a578f1"
NEXT_PUBLIC_BODY_OPTIONS=5
NEXT_PUBLIC_EAR_OPTIONS=6
NEXT_PUBLIC_FACE_OPTIONS=4
Expand Down
44 changes: 37 additions & 7 deletions frontend/src/app/home/Connected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,71 @@ export const provider = new Provider(Network.TESTNET);

export function Connected() {
const [pet, setPet] = useState<Pet>();
const [collectionID, setCollectionID] = useState<string>();
const { account, network } = useWallet();

const fetchPet = useCallback(async () => {
if (!account?.address) return;

const payload = {
const getAptogotchiPayload = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: inline to L25 if this variable isn't being used anywhere else

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it's kinda nice to give a name to it to improve readability. But maybe I missed some benefit of making it inline.

function: `${process.env.NEXT_PUBLIC_CONTRACT_ADDRESS}::main::get_aptogotchi`,
type_arguments: [],
arguments: [account.address],
};

const response = await provider.view(payload);
const aptogotchiResponse = await provider.view(getAptogotchiPayload);

const noPet = ["", "0", "0", "0x"];

if (JSON.stringify(response) !== JSON.stringify(noPet)) {
if (JSON.stringify(aptogotchiResponse) !== JSON.stringify(noPet)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't stringify just to do a comparison. We should compare named values so that it's more readable.

For example:

const [name, birthday, energyPoints, parts) = await provider.view(getAptogotchiPayload);
const noPet = {name: "", birthday: 0, energyPoints: 0, parts: 0x};
if (birthday !== noPet.birthday) {
...
}
if (aptogotchiResponse

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),
});
}
}, [account?.address]);

const fetchCollectionID = useCallback(async () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would inline this function into L66 if it's the only place used.

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[];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more tight typing if it as [string] or [0x${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 (
<div className="flex flex-col gap-3 p-3">
{pet ? <Pet pet={pet} setPet={setPet} /> : <Mint fetchPet={fetchPet} />}
{collectionID ? (
pet ? (
<Pet pet={pet} setPet={setPet} collectionID={collectionID} />
0xZihan marked this conversation as resolved.
Show resolved Hide resolved
) : (
<Mint fetchPet={fetchPet} />
)
) : null}
</div>
);
}
111 changes: 111 additions & 0 deletions frontend/src/app/home/Pet/Collection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"use client";

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);

export interface CollectionProps {
collectionID: string;
}

export type Collection = {
collection_id: string;
collection_name: string;
creator_address: string;
uri: string;
current_supply: any;
};

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<Collection>();
const [collectionHolders, setCollectionHolders] =
useState<CollectionHolder[]>();

const fetchCollection = useCallback(async () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can also be inlined

if (!account?.address) return;

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 } }
) {
owner_address
}
}
`,
variables: {
collection_id: padAddressIfNeeded(collectionID),
},
};

const collectionResponse: CollectionResponse =
await provider.indexerClient.queryIndexer(getCollectionDataGql);

setCollection(collectionResponse.current_collections_v2[0]);
setCollectionHolders(
collectionResponse.current_collection_ownership_v2_view
);
}, [account?.address]);

useEffect(() => {
if (!account?.address || !network) return;

fetchCollection();
}, [account?.address, fetchCollection, network]);

const collectionComponent = (
<div className="nes-field">
<label htmlFor="owner_field">
Aptogotchi Minted: {collection?.current_supply}
</label>
<label htmlFor="owner_field">All Holders</label>
<ul className="nes-list is-disc">
<label>
{JSON.stringify(
collectionHolders?.map(
(holder) => holder.owner_address.substring(0, 5) + "..."
)
)}
</label>
</ul>
</div>
);

return (
<div className="flex flex-col gap-8">
<div className="flex flex-col gap-2">{collectionComponent}</div>
</div>
);
}
5 changes: 4 additions & 1 deletion frontend/src/app/home/Pet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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;
Expand All @@ -15,9 +16,10 @@ export interface Pet {
interface PetProps {
pet: Pet;
setPet: Dispatch<SetStateAction<Pet | undefined>>;
collectionID: string;
}

export function Pet({ pet, setPet }: PetProps) {
export function Pet({ pet, setPet, collectionID }: PetProps) {
const [selectedAction, setSelectedAction] = useState<PetAction>("feed");

return (
Expand All @@ -34,6 +36,7 @@ export function Pet({ pet, setPet }: PetProps) {
avatarStyle
/>
<PetDetails pet={pet} setPet={setPet} />
<Collection collectionID={collectionID} />
</div>
<div className="flex flex-col gap-8 w-[680px] h-full">
<Actions
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/utils/address.ts
Original file line number Diff line number Diff line change
@@ -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)}`;
0xZihan marked this conversation as resolved.
Show resolved Hide resolved
}
53 changes: 0 additions & 53 deletions move/.idea/workspace.xml

This file was deleted.

4 changes: 4 additions & 0 deletions move/Move.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ upgrade_policy = "compatible"
[addresses]
aptogotchi = '_'

# used for testing so you don't need to manually pass in the address in cli
[dev-addresses]
aptogotchi = "0x100"
0xZihan marked this conversation as resolved.
Show resolved Hide resolved

[dependencies.AptosFramework]
git = 'https://github.com/aptos-labs/aptos-core.git'
rev = 'main'
Expand Down
25 changes: 25 additions & 0 deletions move/sh_scripts/dev_setup.sh
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions move/sh_scripts/move_publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

set -e

echo "##### Publishing module #####"

PROFILE=testnet-2
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
Loading