Skip to content

Commit

Permalink
Merge pull request #1 from arjanjohan/block-explorer
Browse files Browse the repository at this point in the history
Debug tab
  • Loading branch information
arjanjohan authored Jul 6, 2024
2 parents 4b64cf7 + 1632357 commit 8353df5
Show file tree
Hide file tree
Showing 48 changed files with 2,510 additions and 410 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged --verbose
# yarn lint-staged --verbose
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<h4 align="center">
<a href="https://github.com/arjanjohan/scaffold-move">Documentation</a> |
<a href="https://scaffoldeth.io">Website</a>
<a href="https://scaffold-move-chi.vercel.app/">Website</a>
</h4>

🧪 An open-source, up-to-date toolkit for building decentralized applications (dapps) on Move blockchains like Aptos and Movement M1. It's designed to make it easier for developers to create and deploy smart contracts and build user interfaces that interact with those contracts.
Expand Down Expand Up @@ -63,15 +63,27 @@ Visit your app on: `http://localhost:3000`. You can interact with your smart con

**What's next**:

- Edit your smart contract `YourContract.sol` in `packages/hardhat/contracts`
- Edit your smart contract `OnchainBio.move` in `packages/move/sources`
- Edit your frontend homepage at `packages/nextjs/app/page.tsx`. For guidance on [routing](https://nextjs.org/docs/app/building-your-application/routing/defining-routes) and configuring [pages/layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts) checkout the Next.js documentation.
- Edit your deployment scripts in `packages/hardhat/deploy`
- Edit your smart contract test in: `packages/hardhat/test`. To run test use `yarn hardhat:test`
<!-- - Edit your smart contract test in: `packages/hardhat/test`. To run test use `yarn hardhat:test` -->

## Documentation
## TODO:

Coming soon.
- Styling wallet connect button
- Store network data in scaffold-config
- Debug page
- Display Resources?
- Read and write functionality
- Make Move hooks for ScaffoldReadContract and ScaffoldWriteContract
- Add `aptos init` script that runs `aptos init` and then copies the new address to the `move.toml` file.
- Hot contract reload: Add `aptos move deploy` script that copies the address to the frontend file `addresses.ts`.

## Contributing to Scaffold-ETH 2
## Links

We welcome contributions to Scaffold-Move!
- [Presentation video]()
- [Presentation slides]()
- [Website](https://scaffold-move-chi.vercel.app/)

## Team

- [arjanjohan](https://x.com/arjanjohan/)
Binary file added assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logo2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"private": true,
"workspaces": {
"packages": [
"packages/hardhat",
"packages/move",
"packages/nextjs"
]
},
"scripts": {
"account": "",
"chain": "",
"deploy": "",
"deploy": "cd packages/move && movement aptos move publish && node scripts/loadContracts.js",
"compile": "",
"test": "",
"format": "yarn next:format && yarn hardhat:format",
Expand All @@ -28,10 +28,15 @@
},
"packageManager": "[email protected]",
"devDependencies": {
"@types/js-yaml": "^4",
"husky": "^8.0.1",
"lint-staged": "^13.0.3"
},
"engines": {
"node": ">=18.17.0"
},
"dependencies": {
"aptos": "^1.21.0",
"js-yaml": "^4.1.0"
}
}
2 changes: 1 addition & 1 deletion packages/move/Move.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ git = 'https://github.com/aptos-labs/aptos-core.git'
rev = 'main'
subdir = 'aptos-move/framework/aptos-framework'
[addresses]
OnchainBio='0xa8e7c149c80c604a71a785217fb3783b461d34945844d8a8609dc0ef06c70b92'
OnchainBio='0x4295cca96321b2807473c0df06fa0ec4b1e22e612f8577cc36406d8c0e67630c'
157 changes: 157 additions & 0 deletions packages/nextjs/app/bio/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"use client";

import { useState } from "react";
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
import { InputTransactionData, useWallet } from "@aptos-labs/wallet-adapter-react";
import type { NextPage } from "next";
import { InputBase } from "~~/components/scaffold-eth";
import deployedModules from "~~/contracts/deployedModules";
import useSubmitTransaction from "~~/hooks/scaffold-move/useSubmitTransaction";
import { useGetAccountModules } from "~~/hooks/scaffold-move/useGetAccountModules";

// TODO: move this somewhere global
const aptosConfig = new AptosConfig({
network: Network.CUSTOM,
fullnode: "https://aptos.devnet.m1.movementlabs.xyz",
indexer: "https://indexer.devnet.m1.movementlabs.xyz/",
faucet: "https://faucet2.movementlabs.xyz",
});
const aptos = new Aptos(aptosConfig);

const ONCHAIN_BIO = deployedModules.devnet.onchain_bio.abi;

const OnchainBio: NextPage = () => {
const { account } = useWallet();

const [inputName, setInputName] = useState<string>("");
const [inputBio, setInputBio] = useState<string>("");

const [accountHasBio, setAccountHasBio] = useState(false);
const [currentName, setCurrentName] = useState(null);
const [currentBio, setCurrentBio] = useState(null);

const {data, isLoading, error} = useGetAccountModules(ONCHAIN_BIO.address);
console.log("useGetAccountModules", data, "isLoading", isLoading, "error", error);


const {submitTransaction, transactionResponse, transactionInProcess} =
useSubmitTransaction();

const fetchBio = async () => {
if (!account) {
console.log("No account");
return [];
}
try {

const resourceName = "Bio";
const bioResource = await aptos.getAccountResource({
accountAddress: account?.address,
resourceType: `${ONCHAIN_BIO.address}::${ONCHAIN_BIO.name}::${resourceName}`,
});
setAccountHasBio(true);
if (bioResource) {
console.log("Name:", bioResource.name, "Bio:", bioResource.bio);
setCurrentName(bioResource.name);
setCurrentBio(bioResource.bio);
} else {
setCurrentName(null);
setCurrentBio(null);
console.log("no bio");
}
} catch (e: any) {
setAccountHasBio(false);
}
};

async function registerBio() {
if (inputName === null || inputBio === null) {
// error msg popup
} else {
const onchainName = inputName;
const onchainBio = inputBio;
const functionName = "register";
const transaction: InputTransactionData = {
data: {
function: `${ONCHAIN_BIO.address}::${ONCHAIN_BIO.name}::${functionName}`,
functionArguments: [onchainName, onchainBio],
},
};
await submitTransaction(transaction);

fetchBio();

// TODO: no transactionResponse?
if (transactionResponse?.transactionSubmitted) {
console.log("function_interacted", {
txn_status: transactionResponse.success ? "success" : "failed",
});
}
}
}

return (
<>
<div className="flex items-center flex-col flex-grow ">
<div className="flex flex-col items-center bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<div className="text-xl">Your Onchain Bio</div>
</div>

{/* Create bio */}
{/* <div className="flex flex-col gap-1.5 w-full"> */}

<div className="flex flex-col space-y-4 bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<div className="flex items-center ml-2">
<span className="text-xs font-medium mr-2 leading-none">Your name</span>
</div>
<div className="w-full flex flex-col space-y-2">
<InputBase placeholder="Name" value={inputName} onChange={value => setInputName(value)} />
</div>
<div className="flex items-center ml-2">
<span className="text-xs font-medium mr-2 leading-none">Your bio</span>
</div>{" "}
<div className="w-full flex flex-col space-y-2">
<InputBase placeholder="Bio" value={inputBio} onChange={value => setInputBio(value)} />
</div>
<button
className="btn btn-secondary mt-2"
onClick={async () => {
try {
await registerBio();
} catch (err) {
console.error("Error calling registerBio function");
}
}}
>
Register Bio
</button>
</div>

{/* Fetch bio */}
<div className="flex flex-col items-center space-y-4 bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<button
className="btn btn-secondary mt-2"
onClick={async () => {
try {
await fetchBio();
} catch (err) {
console.error("Error calling fetchBio function");
}
}}
>
Fetch Bio
</button>
</div>

{accountHasBio && !transactionInProcess && (
<div>
<div>{currentName}</div>
<div>{currentBio}</div>
</div>
)}
</div>
</>
);
};

export default OnchainBio;
6 changes: 4 additions & 2 deletions packages/nextjs/app/blockexplorer/address/[address]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import fs from "fs";
import path from "path";
import { hardhat } from "viem/chains";
import { AddressComponent } from "~~/app/blockexplorer/_components/AddressComponent";
import deployedContracts from "~~/contracts/deployedContracts";

import deployedModules from "~~/contracts/deployedModules";

import { isZeroAddress } from "~~/utils/scaffold-eth/common";
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";

Expand Down Expand Up @@ -37,7 +39,7 @@ async function fetchByteCodeAndAssembly(buildInfoDirectory: string, contractPath
}

const getContractData = async (address: string) => {
const contracts = deployedContracts as GenericContractsDeclaration | null;
const contracts = deployedModules as GenericContractsDeclaration | null;
const chainId = hardhat.id;
let contractPath = "";

Expand Down
13 changes: 12 additions & 1 deletion packages/nextjs/app/debug/_components/DebugContracts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@ import { useLocalStorage } from "usehooks-ts";
import { BarsArrowUpIcon } from "@heroicons/react/20/solid";
import { ContractUI } from "~~/app/debug/_components/contract";
import { ContractName } from "~~/utils/scaffold-eth/contract";
import { getAllContracts } from "~~/utils/scaffold-eth/contractsData";
import { getAllContracts } from "~~/utils/scaffold-move/contractsData";
// import moveContracts from "~~/contracts/moveContracts";
// import { useGetAccountModules } from "~~/hooks/scaffold-move/useGetAccountModules";
// const ONCHAIN_BIO = moveContracts.ONCHAIN_BIO;


const selectedContractStorageKey = "scaffoldEth2.selectedContract";
const contractsData = getAllContracts();
const contractNames = Object.keys(contractsData) as ContractName[];

// let contractNames = [] as ContractName[];

export function DebugContracts() {



const selectedContractStorageKey = "scaffoldEth2.selectedContract";

const [selectedContract, setSelectedContract] = useLocalStorage<ContractName>(
selectedContractStorageKey,
contractNames[0],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
import { Abi, AbiFunction } from "abitype";
import { ReadOnlyFunctionForm } from "~~/app/debug/_components/contract";
import { Contract, ContractName, GenericContract, InheritedFunctions } from "~~/utils/scaffold-eth/contract";
import { FunctionForm } from "~~/app/debug/_components/contract";
import { Contract, ContractName } from "~~/utils/scaffold-move/contract";

export const ContractReadMethods = ({ deployedContractData }: { deployedContractData: Contract<ContractName> }) => {
if (!deployedContractData) {
export const ContractReadMethods = ({
deployedContractData
}: {
deployedContractData: Contract<ContractName>
}) => {
if (!deployedContractData || deployedContractData.abi === undefined) {
return null;
}

const functionsToDisplay = (
((deployedContractData.abi || []) as Abi).filter(part => part.type === "function") as AbiFunction[]
)
.filter(fn => {
const isQueryableWithParams =
(fn.stateMutability === "view" || fn.stateMutability === "pure") && fn.inputs.length > 0;
return isQueryableWithParams;
})
.map(fn => {
return {
fn,
inheritedFrom: ((deployedContractData as GenericContract)?.inheritedFunctions as InheritedFunctions)?.[fn.name],
};
})
.sort((a, b) => (b.inheritedFrom ? b.inheritedFrom.localeCompare(a.inheritedFrom) : 1));
const functionsToDisplay = deployedContractData.abi.exposed_functions.filter((fn) =>
fn.is_view,
);

if (!functionsToDisplay.length) {
return <>No read methods</>;
}

return (
<>
{functionsToDisplay.map(({ fn, inheritedFrom }) => (
<ReadOnlyFunctionForm
abi={deployedContractData.abi as Abi}
contractAddress={deployedContractData.address}
abiFunction={fn}
key={fn.name}
inheritedFrom={inheritedFrom}
{/* {functionsToDisplay.map(({ fn }) => (
<WriteOnlyFunctionForm
module={deployedContractData}
fn={fn}
/>
))} */}
<FunctionForm
module={deployedContractData.abi}
fn={functionsToDisplay[0]}
write={false}
/>
))}
</>
);
};
Loading

0 comments on commit 8353df5

Please sign in to comment.