From 2e289c44f7d3c37b768652c89460f38605966abb Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Mon, 24 Jun 2024 21:28:05 +0530 Subject: [PATCH 01/22] attestation registry --- .../nextjs/contracts/deployedContracts.ts | 146 ++++++++++------- packages/nextjs/scaffold.config.ts | 2 +- .../contracts/src/AttestationRegistry.cairo | 151 ++++++++++++++++++ packages/snfoundry/contracts/src/lib.cairo | 4 +- packages/snfoundry/scripts-ts/deploy.ts | 25 ++- 5 files changed, 260 insertions(+), 68 deletions(-) create mode 100644 packages/snfoundry/contracts/src/AttestationRegistry.cairo diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index f04dc0a..1b3466d 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -5,14 +5,15 @@ const deployedContracts = { devnet: { - SchemaRegistry: { + AttestationRegistry: { address: - "0x01e118bd0158076bbe64f87f5519ee7c074ca5cb618a80bf7741b2ec3187aafb", + "0x07c59f28a693a4d629f0b0358ae52649ca3e6743e111bedc0c822ee76ece3387", abi: [ { type: "impl", - name: "SchemaRegistryImpl", - interface_name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "AttestationRegistryImpl", + interface_name: + "contracts::AttestationRegistry::IAttestationRegistry", }, { type: "struct", @@ -48,14 +49,22 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "contracts::AttestationRegistry::IAttestationRegistry", items: [ { type: "function", - name: "register", + name: "attest", inputs: [ { - name: "schema", + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "data", type: "core::byte_array::ByteArray", }, { @@ -70,54 +79,58 @@ const deployedContracts = { ], state_mutability: "external", }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [ { - type: "function", - name: "get_schema", - inputs: [ - { - name: "uid", - type: "core::integer::u128", - }, - ], - outputs: [ - { - type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", - }, - ], - state_mutability: "view", + name: "schema_registry_address", + type: "core::starknet::contract_address::ContractAddress", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "struct", members: [ { - name: "uid", - type: "core::integer::u128", + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", kind: "key", }, { - name: "caller", + name: "attester", type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "uid", + type: "core::integer::u128", kind: "data", }, { - name: "schema_record", - type: "core::byte_array::ByteArray", + name: "schema_uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "timestamp", + type: "core::integer::u64", kind: "data", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Event", + name: "contracts::AttestationRegistry::AttestationRegistry::Event", kind: "enum", variants: [ { - name: "Registered", - type: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "Attested", + type: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "nested", }, ], @@ -126,14 +139,15 @@ const deployedContracts = { }, }, sepolia: { - SchemaRegistry: { + AttestationRegistry: { address: - "0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87", + "0x077cf1b7bb4ce74559dbbab85714f1d69e520657670639ff77c9e99eedeb13f6", abi: [ { type: "impl", - name: "SchemaRegistryImpl", - interface_name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "AttestationRegistryImpl", + interface_name: + "contracts::AttestationRegistry::IAttestationRegistry", }, { type: "struct", @@ -169,14 +183,22 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "contracts::AttestationRegistry::IAttestationRegistry", items: [ { type: "function", - name: "register", + name: "attest", inputs: [ { - name: "schema", + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "data", type: "core::byte_array::ByteArray", }, { @@ -191,54 +213,58 @@ const deployedContracts = { ], state_mutability: "external", }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [ { - type: "function", - name: "get_schema", - inputs: [ - { - name: "uid", - type: "core::integer::u128", - }, - ], - outputs: [ - { - type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", - }, - ], - state_mutability: "view", + name: "schema_registry_address", + type: "core::starknet::contract_address::ContractAddress", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "struct", members: [ { - name: "uid", - type: "core::integer::u128", + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", kind: "key", }, { - name: "caller", + name: "attester", type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "uid", + type: "core::integer::u128", kind: "data", }, { - name: "schema_record", - type: "core::byte_array::ByteArray", + name: "schema_uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "timestamp", + type: "core::integer::u64", kind: "data", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Event", + name: "contracts::AttestationRegistry::AttestationRegistry::Event", kind: "enum", variants: [ { - name: "Registered", - type: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "Attested", + type: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "nested", }, ], diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index fac39e1..ee79a8f 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -9,7 +9,7 @@ export type ScaffoldConfig = { }; const scaffoldConfig = { - targetNetworks: [chains.sepolia], + targetNetworks: [chains.devnet], // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: process.env.NEXT_PUBLIC_PROVIDER_URL || "", diff --git a/packages/snfoundry/contracts/src/AttestationRegistry.cairo b/packages/snfoundry/contracts/src/AttestationRegistry.cairo new file mode 100644 index 0000000..c57db7a --- /dev/null +++ b/packages/snfoundry/contracts/src/AttestationRegistry.cairo @@ -0,0 +1,151 @@ +use starknet::ContractAddress; +use super::SchemaRegistry::{ISchemaRegistry, ISchemaRegistryDispatcher}; + +#[starknet::interface] +pub trait IAttestationRegistry { + fn attest(ref self: TContractState, schema_uid: u128, recipient: ContractAddress, data: ByteArray, revocable: bool) -> u128; + // fn revoke(ref self: TContractState, request: RevocationRequest); +} + +// Define structs +#[derive(Drop, Serde, starknet::Store)] +struct Attestation { + uid: u128, + schema_uid: u128, + time: u64, + // expiration_time: u64, + recipient: ContractAddress, + attester: ContractAddress, + data: ByteArray, +} + +#[derive(Drop, Serde, starknet::Store)] +struct AttestationRequest { + schema_uid: u128, + recipient: ContractAddress, + // expiration_time: u64, + data: ByteArray, + revocable: bool +} + +// #[derive(Drop, Serde, starknet::Store)] +// struct RevocationRequestData { +// uid: felt252, +// value: u256, +// } + +// #[derive(Drop, Serde, starknet::Store)] +// struct RevocationRequest { +// schema: felt252, +// data: RevocationRequestData, +// } + + +#[starknet::contract] +mod AttestationRegistry { + use core::traits::Into; + use contracts::SchemaRegistry::ISchemaRegistryDispatcherTrait; + use starknet::{get_caller_address, get_block_timestamp}; + use super::{ + ContractAddress, IAttestationRegistry, AttestationRequest, Attestation, + ISchemaRegistryDispatcher + }; + + // Define constants + const EMPTY_UID: u128 = 0; + const NO_EXPIRATION_TIME: u64 = 0; + + // Events + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + Attested: Attested, + // Revoked: Revoked, + // Timestamped: Timestamped, + // RevokedOffchain: RevokedOffchain, + } + + #[derive(Drop, starknet::Event)] + struct Attested { + #[key] + recipient: ContractAddress, + #[key] + attester: ContractAddress, + uid: u128, + #[key] + schema_uid: u128, + timestamp: u64, + } + + // // The global mapping between attestations and their UIDs. + // mapping(bytes32 uid => Attestation attestation) private _db; + + // // The global mapping between data and their timestamps. + // mapping(bytes32 data => uint64 timestamp) private _timestamps; + + // // The global mapping between data and their revocation timestamps. + // mapping(address revoker => mapping(bytes32 data => uint64 timestamp) timestamps) private _revocationsOffchain; + #[storage] + struct Storage { + schema_registry: ContractAddress, + db: LegacyMap::, + timestamps: LegacyMap::, + current_uid: u128, + // revocations_offchain: LegacyMap::<(ContractAddress, felt252), u64>, + } + + // Constructor +#[constructor] + fn constructor(ref self: ContractState, schema_registry_address: ContractAddress) { + self.schema_registry.write(schema_registry_address); + } + + #[abi(embed_v0)] + impl AttestationRegistryImpl of IAttestationRegistry { + fn attest(ref self: ContractState, schema_uid: u128, recipient: ContractAddress, data: ByteArray, revocable: bool) -> u128 { + let contract_address = self.schema_registry.read(); + // let (fetched_uid, fetched_revocable, fetched_schema) = ISchemaRegistryDispatcher { contract_address } + // .get_schema(schema_uid); + + // assert!(fetched_uid != EMPTY_UID, "Schema Not Found"); + // assert!( + // request.expiration_time != NO_EXPIRATION_TIME + // && request.expiration_time <= get_block_timestamp(), + // "Invalid Expiration Time" + // ); + // assert!(!fetched_revocable && revocable, "Irrevocable"); + + let mut attestation = Attestation { + uid: EMPTY_UID, + schema_uid, + time: get_block_timestamp(), + // expiration_time: request.expiration_time, + recipient, + attester: get_caller_address(), + data + }; + + self.current_uid.write(self.current_uid.read() + 1); + let uid = self.current_uid.read(); + attestation.uid = uid; + + self.db.write(uid, attestation); + + self + .emit( + Attested { + recipient, + attester: get_caller_address(), + uid, + schema_uid, + timestamp: get_block_timestamp() + } + ); + + uid + } + + // fn revoke(ref self: ContractState, request: RevocationRequest) {} + } +} + diff --git a/packages/snfoundry/contracts/src/lib.cairo b/packages/snfoundry/contracts/src/lib.cairo index dbd2a4b..02bd141 100644 --- a/packages/snfoundry/contracts/src/lib.cairo +++ b/packages/snfoundry/contracts/src/lib.cairo @@ -1,5 +1,5 @@ -mod SAS; -mod YourContract; +// mod SAS; +mod AttestationRegistry; mod SchemaRegistry; #[cfg(test)] mod test { diff --git a/packages/snfoundry/scripts-ts/deploy.ts b/packages/snfoundry/scripts-ts/deploy.ts index 1e5e502..90f308b 100644 --- a/packages/snfoundry/scripts-ts/deploy.ts +++ b/packages/snfoundry/scripts-ts/deploy.ts @@ -1,14 +1,29 @@ import { deployContract, deployer, exportDeployments } from "./deploy-contract"; const deployScript = async (): Promise => { + // await deployContract( + // { + // owner: deployer.address, // the deployer address is the owner of the contract + // }, + // "SchemaRegistry", + // ); + await deployContract( - { - owner: deployer.address, // the deployer address is the owner of the contract - }, - "SchemaRegistry" - ); + { + schema_registry_address: "0x048ec8a62f68659ed94e57e497e154d96cc4d5356ef35a58c6b3f4e034325a8f", // the deployer address is the owner of the contract, + }, + "AttestationRegistry" +); }; +// await deployContract( +// { +// schema_registry_address: "0x075d3a77b16fdb4609b981f6f8ccb393470b67ee64a832139931483f099c36d8", // the deployer address is the owner of the contract, +// }, +// // "SchemaRegistry", +// "AttestationRegistry" +// ); + deployScript() .then(() => { exportDeployments(); From b9c8c248f4931f34ce9b733aedc346055932dcb2 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Mon, 24 Jun 2024 19:13:12 +0300 Subject: [PATCH 02/22] minor fix --- .../app/dashboard/attestations/page.tsx | 202 ++++++++++-------- packages/nextjs/scaffold.config.ts | 2 +- 2 files changed, 111 insertions(+), 93 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 8535082..7d8d685 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -1,136 +1,154 @@ "use client"; import React, { useState, useEffect } from "react"; import Link from "next/link"; -import { fetchAllAttestations, shortAddress } from "~~/utils/utils"; +import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import Modal from "~~/components/Modal"; -import CreateAttestationForm from "~~/components/forms/CreateAttestationForm"; -const Dashboard = () => { - const [attestations, setAttestations] = useState([]); - const [stats, setStats] = useState<{ - totalAtestations: number; - totalSchemas: number; - totalAttestors: number; - }>({ - totalAtestations: 0, - totalSchemas: 0, - totalAttestors: 0, +import RegisterSchemaForm from "~~/components/forms/RegisterSchemaForm"; + +const Attestations = () => { + const [totalSchemas, setTotalSchemas] = useState(0); + const [schemas, setSchemas] = useState([]); + + const { + data: eventData, + isLoading, + error: err, + } = useScaffoldEventHistory({ + contractName: "AttestationRegistry", + eventName: "contracts::AttestationRegistry::AttestationRegistry::Attested", + fromBlock: BigInt(0), + blockData: true, + transactionData: false, + receiptData: false, + watch: true, + enabled: true, }); - const getAttestations = async () => { - try { - const attestationData = await fetchAllAttestations(); - } catch (error) { - console.error("Error fetching attestations:", error); +/* struct Attested { + #[key] + recipient: ContractAddress, + #[key] + attester: ContractAddress, + uid: u128, + #[key] + schema_uid: u128, + timestamp: u64, +} + */ + useEffect(() => { + if (eventData) { + console.log(eventData); + setTotalSchemas(eventData.length); + setSchemas( + eventData.map((event) => ({ + recipient: event.args.recipient, + attester: event.args.attester, + uid: event.args.uid, + schema: event.args.schema_uid, + timestamp: event.args.timestamp, + })), + ); } - }; + }, [eventData]); - const AttestationLink = ({ uid }: { uid: string }) => ( + const SchemaLink = ({ uid }: { uid: string }) => ( - {shortAddress(uid)} + {uid.toString()} ); - const DashboardStats = ({ - totalAtestations, - totalSchemas, - totalAttestors, - }: { - totalAtestations: number; - totalSchemas: number; - totalAttestors: number; - }) => ( + const DashboardStats = ({ totalSchemas }: { totalSchemas: number }) => (
-
-
- {totalAtestations} -
-
Total Attestations
-
{totalSchemas}
Total Schemas
-
-
- {totalAttestors} -
-
Total Attestors
-
); - useEffect(() => { - getAttestations(); - }, []); return (
-
+

- Attestation Scan + Solas Schemas

- Showing the most recent Solas Attestations. + Showing the most recent Solas Schemas.

+ ( )} > - +
- -
- - - - - - - - - - - - - {attestations.map((attestation) => ( - - - - - - - + + {isLoading ? ( +
+ +
+ ) : ( +
+
UIDSchemaFromToTypeAge
- - - {attestation.schema} - - {attestation.from} - - {attestation.to} - - {attestation.type} - - {attestation.age} -
+ + + + + + + - ))} - -
UIDAttesterRecipientSchema UITimestamp
-
+ + + + {schemas.map((schema, index) => ( + + + + + + {schema.attester} + + + {schema.recipient} + + + {schema.schema} + + + {schema.timestamp} + + + ))} + + +
+ )}
View all attestations @@ -142,4 +160,4 @@ const Dashboard = () => { ); }; -export default Dashboard; +export default Attestations; diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index ee79a8f..fac39e1 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -9,7 +9,7 @@ export type ScaffoldConfig = { }; const scaffoldConfig = { - targetNetworks: [chains.devnet], + targetNetworks: [chains.sepolia], // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: process.env.NEXT_PUBLIC_PROVIDER_URL || "", From b2853860bfecd4603389b8787a3052d526f789b0 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Mon, 24 Jun 2024 19:32:14 +0300 Subject: [PATCH 03/22] minor fix --- .../app/dashboard/attestations/page.tsx | 10 +- .../forms/CreateAttestationForm.tsx | 145 ++++++++---------- 2 files changed, 69 insertions(+), 86 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 7d8d685..0ba9d7f 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect } from "react"; import Link from "next/link"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import Modal from "~~/components/Modal"; -import RegisterSchemaForm from "~~/components/forms/RegisterSchemaForm"; +import CreateAttestationForm from "~~/components/forms/CreateAttestationForm"; const Attestations = () => { const [totalSchemas, setTotalSchemas] = useState(0); @@ -73,10 +73,10 @@ const Attestations = () => {

- Solas Schemas + Solas Attestations

- Showing the most recent Solas Schemas. + Showing the most recent Solas Attestations.

@@ -90,7 +90,7 @@ const Attestations = () => { )} > - +
@@ -120,7 +120,7 @@ const Attestations = () => { UID Attester Recipient - Schema UI + Schema UID Timestamp diff --git a/packages/nextjs/components/forms/CreateAttestationForm.tsx b/packages/nextjs/components/forms/CreateAttestationForm.tsx index 84a0bb8..d8b5ea0 100644 --- a/packages/nextjs/components/forms/CreateAttestationForm.tsx +++ b/packages/nextjs/components/forms/CreateAttestationForm.tsx @@ -1,31 +1,38 @@ "use client"; -import { useEffect } from "react"; +import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -import { useAccount, useContractRead } from "@starknet-react/core"; -import { displayTxResult } from "~~/app/debug/_components/contract/utilsDisplay"; -import ERC20_ABI from "~~/utils/solas-abis/ERC20.json"; +import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; const CreateAttestationForm = () => { - const testAddress = - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"; - const toAddress = - "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"; - - const { data, isError, isLoading, error } = useContractRead({ - functionName: "balanceOf", - args: [toAddress], - abi: ERC20_ABI, - address: testAddress, - watch: true, - }); + const [schema, setSchema] = useState(0); + const[recipient, setRecipient] = useState(""); + const[data, setData] = useState(""); + const [revocable, setRevocable] = useState(false); const router = useRouter(); - const isPending = false; - const isConfirming = false; - const isConfirmed = false; - const isSuccess = false; + const { writeAsync, isSuccess, isPending, isError } = + useScaffoldWriteContract({ + contractName: "AttestationRegistry", + functionName: "attest", + args: [ schema, recipient, data, revocable ], + }); + + const handleSubmit = async (formData: FormData) => { + const revocableFetched = formData.get("revocable") as string; + const recipient = formData.get("recipient") as string; + const data = formData.get("data") as string; + + setSchema(0); + setRevocable(revocableFetched === "true"); + try { + await writeAsync({ + args: [ schema, recipient, data, revocable ], + }); + } catch (err) { + console.error("Error submitting transaction:", err); + } + }; const LoadingSpinner = ( { ); - useEffect(() => { - if (isConfirmed) { - // redirect to dashboard - setTimeout(() => { - router.push("/dashboard"); - }, 5000); - } - }, [isPending, isConfirming, isConfirmed, router]); - - const handleSubmit = (formData: FormData) => {}; - return (
-

Make Attestation

-
+

Register Schema

+ { /> - {!isPending && !isConfirming && ( - - )} - {(isPending || isConfirming) && ( -
- {LoadingSpinner} -
- )} + + Revocable + +
- {isPending && !isSuccess && ( -
- Please sign the transaction with your wallet. -
- )} - {isSuccess && isConfirming && ( -
- Waiting for confirmation... + {isPending && ( +
+ {LoadingSpinner}
)} - {isConfirmed && ( + {isSuccess && (
)} - {isLoading &&
Loading ...
} - {isError || (!data &&
{error?.message}
)} - {data && ( -
{displayTxResult(data, false)}
+ {isError && ( +
+ Error submitting transaction. +
)}
); }; + export default CreateAttestationForm; From 7fa274c15ee9061651724a3d7f1f1a1940de137a Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Mon, 24 Jun 2024 19:34:11 +0300 Subject: [PATCH 04/22] Update CreateAttestationForm.tsx --- packages/nextjs/components/forms/CreateAttestationForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/components/forms/CreateAttestationForm.tsx b/packages/nextjs/components/forms/CreateAttestationForm.tsx index d8b5ea0..ca0d2c7 100644 --- a/packages/nextjs/components/forms/CreateAttestationForm.tsx +++ b/packages/nextjs/components/forms/CreateAttestationForm.tsx @@ -54,12 +54,12 @@ const CreateAttestationForm = () => { return (
-

Register Schema

+

Create Attestation

From 3d99e64da868f86e67423be01f4ce4a979757ea7 Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Mon, 24 Jun 2024 22:08:25 +0530 Subject: [PATCH 05/22] updated deployed contract --- .../nextjs/contracts/deployedContracts.ts | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 1b3466d..affdb5c 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -271,6 +271,125 @@ const deployedContracts = { }, ], }, + SchemaRegistry: { + address: + "0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87", + abi: [ + { + type: "impl", + name: "SchemaRegistryImpl", + interface_name: "contracts::SchemaRegistry::ISchemaRegistry", + }, + { + type: "struct", + name: "core::byte_array::ByteArray", + members: [ + { + name: "data", + type: "core::array::Array::", + }, + { + name: "pending_word", + type: "core::felt252", + }, + { + name: "pending_word_len", + type: "core::integer::u32", + }, + ], + }, + { + type: "enum", + name: "core::bool", + variants: [ + { + name: "False", + type: "()", + }, + { + name: "True", + type: "()", + }, + ], + }, + { + type: "interface", + name: "contracts::SchemaRegistry::ISchemaRegistry", + items: [ + { + type: "function", + name: "register", + inputs: [ + { + name: "schema", + type: "core::byte_array::ByteArray", + }, + { + name: "revocable", + type: "core::bool", + }, + ], + outputs: [ + { + type: "core::integer::u128", + }, + ], + state_mutability: "external", + }, + { + type: "function", + name: "get_schema", + inputs: [ + { + name: "uid", + type: "core::integer::u128", + }, + ], + outputs: [ + { + type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "event", + name: "contracts::SchemaRegistry::SchemaRegistry::Registered", + kind: "struct", + members: [ + { + name: "uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "caller", + type: "core::starknet::contract_address::ContractAddress", + kind: "data", + }, + { + name: "schema_record", + type: "core::byte_array::ByteArray", + kind: "data", + }, + ], + }, + { + type: "event", + name: "contracts::SchemaRegistry::SchemaRegistry::Event", + kind: "enum", + variants: [ + { + name: "Registered", + type: "contracts::SchemaRegistry::SchemaRegistry::Registered", + kind: "nested", + }, + ], + }, + ], + }, }, } as const; From 5af0cd52cb7d27592af76e69d7e56123d8c1ba49 Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 13:59:41 +0530 Subject: [PATCH 06/22] updated deployed contract --- SolasPresentation.md | 41 +++++++++++++++++++ .../nextjs/contracts/deployedContracts.ts | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 SolasPresentation.md diff --git a/SolasPresentation.md b/SolasPresentation.md new file mode 100644 index 0000000..19c10ff --- /dev/null +++ b/SolasPresentation.md @@ -0,0 +1,41 @@ +# Solas + +## Overview + +Solas is a open-source infrastructure public good for making attestations onchain on Starknet. Our motivation was EAS which is deployed on Ethereum mainnet. + +## Architecture + +We've 2 core contracts in Solas: +- Schema Registry - This is the blueprint of the schema, it defines the structure and format of the data. + +- Attestation Registry - This is the contract responsible for making attestation using a schema on Starknet. + +## Example + +An example of how this could be used to attest if a person has participated in StarkHack Hackathon + +Raw Schema +{ + "name": string, + "userAddress": string, + "event": string, + "participated": bool +} + +Example Attesation + +Sender is: StarkHack admin +Recipient is: Contestant +revocable: false +data: { + "name": "Suraj Kohli", + "userAddress": "0x1234567890123456789012345678901234567890", + "event": "StarkHack Hackathon", + "participated": true +} + +## Future Enhancements + +- Ability to refer other attestations +- Allow delegated attestations (Contract receives a signed attestation and attests onchain on behalf of user) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index affdb5c..61c12b1 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -393,4 +393,4 @@ const deployedContracts = { }, } as const; -export default deployedContracts; +export default deployedContracts; \ No newline at end of file From 83828c7d6842748f59b2ecab797b2a9a7de68dbf Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 14:26:24 +0530 Subject: [PATCH 07/22] formatting and linting changes --- .../app/dashboard/attestations/page.tsx | 3 +- .../forms/CreateAttestationForm.tsx | 8 +-- .../nextjs/contracts/deployedContracts.ts | 2 +- .../contracts/src/AttestationRegistry.cairo | 26 ++++++--- packages/snfoundry/contracts/src/SAS.cairo | 58 ++++++++++--------- .../contracts/src/test/Test_sas.cairo | 1 + packages/snfoundry/scripts-ts/deploy.ts | 11 ++-- 7 files changed, 61 insertions(+), 48 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 0ba9d7f..18d3477 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -24,7 +24,7 @@ const Attestations = () => { enabled: true, }); -/* struct Attested { + /* struct Attested { #[key] recipient: ContractAddress, #[key] @@ -125,7 +125,6 @@ const Attestations = () => { - {schemas.map((schema, index) => ( diff --git a/packages/nextjs/components/forms/CreateAttestationForm.tsx b/packages/nextjs/components/forms/CreateAttestationForm.tsx index ca0d2c7..daeee3e 100644 --- a/packages/nextjs/components/forms/CreateAttestationForm.tsx +++ b/packages/nextjs/components/forms/CreateAttestationForm.tsx @@ -5,8 +5,8 @@ import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWri const CreateAttestationForm = () => { const [schema, setSchema] = useState(0); - const[recipient, setRecipient] = useState(""); - const[data, setData] = useState(""); + const [recipient, setRecipient] = useState(""); + const [data, setData] = useState(""); const [revocable, setRevocable] = useState(false); const router = useRouter(); @@ -15,7 +15,7 @@ const CreateAttestationForm = () => { useScaffoldWriteContract({ contractName: "AttestationRegistry", functionName: "attest", - args: [ schema, recipient, data, revocable ], + args: [schema, recipient, data, revocable], }); const handleSubmit = async (formData: FormData) => { @@ -27,7 +27,7 @@ const CreateAttestationForm = () => { setRevocable(revocableFetched === "true"); try { await writeAsync({ - args: [ schema, recipient, data, revocable ], + args: [schema, recipient, data, revocable], }); } catch (err) { console.error("Error submitting transaction:", err); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 61c12b1..affdb5c 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -393,4 +393,4 @@ const deployedContracts = { }, } as const; -export default deployedContracts; \ No newline at end of file +export default deployedContracts; diff --git a/packages/snfoundry/contracts/src/AttestationRegistry.cairo b/packages/snfoundry/contracts/src/AttestationRegistry.cairo index c57db7a..cccf497 100644 --- a/packages/snfoundry/contracts/src/AttestationRegistry.cairo +++ b/packages/snfoundry/contracts/src/AttestationRegistry.cairo @@ -3,8 +3,14 @@ use super::SchemaRegistry::{ISchemaRegistry, ISchemaRegistryDispatcher}; #[starknet::interface] pub trait IAttestationRegistry { - fn attest(ref self: TContractState, schema_uid: u128, recipient: ContractAddress, data: ByteArray, revocable: bool) -> u128; - // fn revoke(ref self: TContractState, request: RevocationRequest); + fn attest( + ref self: TContractState, + schema_uid: u128, + recipient: ContractAddress, + data: ByteArray, + revocable: bool + ) -> u128; +// fn revoke(ref self: TContractState, request: RevocationRequest); } // Define structs @@ -40,11 +46,10 @@ struct AttestationRequest { // data: RevocationRequestData, // } - #[starknet::contract] mod AttestationRegistry { - use core::traits::Into; use contracts::SchemaRegistry::ISchemaRegistryDispatcherTrait; + use core::traits::Into; use starknet::{get_caller_address, get_block_timestamp}; use super::{ ContractAddress, IAttestationRegistry, AttestationRequest, Attestation, @@ -95,14 +100,20 @@ mod AttestationRegistry { } // Constructor -#[constructor] + #[constructor] fn constructor(ref self: ContractState, schema_registry_address: ContractAddress) { self.schema_registry.write(schema_registry_address); } #[abi(embed_v0)] impl AttestationRegistryImpl of IAttestationRegistry { - fn attest(ref self: ContractState, schema_uid: u128, recipient: ContractAddress, data: ByteArray, revocable: bool) -> u128 { + fn attest( + ref self: ContractState, + schema_uid: u128, + recipient: ContractAddress, + data: ByteArray, + revocable: bool + ) -> u128 { let contract_address = self.schema_registry.read(); // let (fetched_uid, fetched_revocable, fetched_schema) = ISchemaRegistryDispatcher { contract_address } // .get_schema(schema_uid); @@ -144,8 +155,7 @@ mod AttestationRegistry { uid } - - // fn revoke(ref self: ContractState, request: RevocationRequest) {} + // fn revoke(ref self: ContractState, request: RevocationRequest) {} } } diff --git a/packages/snfoundry/contracts/src/SAS.cairo b/packages/snfoundry/contracts/src/SAS.cairo index c67730a..bb49674 100644 --- a/packages/snfoundry/contracts/src/SAS.cairo +++ b/packages/snfoundry/contracts/src/SAS.cairo @@ -10,9 +10,9 @@ use starknet::SyscallResult; // use starknet::Store; use starknet::storage_access::Store; use starknet::storage_access::{StorageAddress, StorageBaseAddress}; +use starknet::syscalls::call_contract_syscall; use starknet::syscalls::storage_read_syscall; use starknet::syscalls::storage_write_syscall; -use starknet::syscalls::call_contract_syscall; use starknet::{get_block_timestamp, get_caller_address}; // Define structs @@ -173,31 +173,35 @@ mod SAS { } fn attest(ref self: ContractState, request: AttestationRequest) -> u128 { - - let attestation = Attestation { - uid: EMPTY_UID, - schema_uid: request.schema_uid, - ref_uid: request.refUID, - time: get_block_timestamp(), - expiration_time: request.expirationTime, - recipient: request.recipient, - attester: get_caller_address(), - data: request.data, - }; - - self.current_uid.write(self.current_uid.read() + 1); - let uid = self.current_uid.read(); - let timestamp = get_block_timestamp(); - - self.db.write(uid, attestation); - self.emit(Event::Attested(Attested { - recipient: request.recipient, - attester: get_caller_address(), - uid, - schema_uid: request.schema_uid, - timestamp - })); - + let attestation = Attestation { + uid: EMPTY_UID, + schema_uid: request.schema_uid, + ref_uid: request.refUID, + time: get_block_timestamp(), + expiration_time: request.expirationTime, + recipient: request.recipient, + attester: get_caller_address(), + data: request.data, + }; + + self.current_uid.write(self.current_uid.read() + 1); + let uid = self.current_uid.read(); + let timestamp = get_block_timestamp(); + + self.db.write(uid, attestation); + self + .emit( + Event::Attested( + Attested { + recipient: request.recipient, + attester: get_caller_address(), + uid, + schema_uid: request.schema_uid, + timestamp + } + ) + ); + uid } @@ -218,12 +222,10 @@ mod SAS { fn get_timestamp(self: @ContractState, data: felt252) -> u64 { self.timestamps.read(data) } - } #[generate_trait] impl InternalFunctions of InternalFunctionsTrait { - fn _timestamp(ref self: ContractState, data: felt252, time: u64) { assert(self.timestamps.read(data) == 0, 'Already timestamped'); self.timestamps.write(data, time); diff --git a/packages/snfoundry/contracts/src/test/Test_sas.cairo b/packages/snfoundry/contracts/src/test/Test_sas.cairo index fb4bbeb..ab54b46 100644 --- a/packages/snfoundry/contracts/src/test/Test_sas.cairo +++ b/packages/snfoundry/contracts/src/test/Test_sas.cairo @@ -138,3 +138,4 @@ fn test_attestation_validity() { } // Additional tests can be added for multi-attestation, delegation, and other complex scenarios + diff --git a/packages/snfoundry/scripts-ts/deploy.ts b/packages/snfoundry/scripts-ts/deploy.ts index 90f308b..93a2e8d 100644 --- a/packages/snfoundry/scripts-ts/deploy.ts +++ b/packages/snfoundry/scripts-ts/deploy.ts @@ -9,11 +9,12 @@ const deployScript = async (): Promise => { // ); await deployContract( - { - schema_registry_address: "0x048ec8a62f68659ed94e57e497e154d96cc4d5356ef35a58c6b3f4e034325a8f", // the deployer address is the owner of the contract, - }, - "AttestationRegistry" -); + { + schema_registry_address: + "0x048ec8a62f68659ed94e57e497e154d96cc4d5356ef35a58c6b3f4e034325a8f", // the deployer address is the owner of the contract, + }, + "AttestationRegistry" + ); }; // await deployContract( From 9415544d68e7b9c1e2116e33d7c5d72a84f8c0ce Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 14:29:50 +0530 Subject: [PATCH 08/22] comment tests --- .../contracts/src/test/Test_sas.cairo | 278 +++++++++--------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/packages/snfoundry/contracts/src/test/Test_sas.cairo b/packages/snfoundry/contracts/src/test/Test_sas.cairo index ab54b46..79b51e6 100644 --- a/packages/snfoundry/contracts/src/test/Test_sas.cairo +++ b/packages/snfoundry/contracts/src/test/Test_sas.cairo @@ -1,141 +1,141 @@ -use array::ArrayTrait; -use option::OptionTrait; -use serde::Serde; -use snforge_std::ContractClassTrait; -use traits::TryInto; - -// Helper function to deploy the SAS contract -fn deploy_sas(registry_address: ContractAddress) -> ContractAddress { - let contract = declare("SAS"); - let mut calldata = array![]; - calldata.append_serde(registry_address); - let (contract_address, _) = contract.deploy(@calldata).unwrap(); - contract_address -} - -// Helper function to create a mock schema registry -fn deploy_mock_schema_registry() -> ContractAddress { - // Implement mock schema registry deployment - // For now, we'll just return a dummy address - starknet::contract_address_const::<0x1234>() -} - -#[test] -fn test_sas_deployment() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - assert_eq!( - dispatcher.get_schema_registry(), registry_address, "Should have correct schema registry" - ); -} - -#[test] -fn test_attest() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - let schema = 0x1234_felt252; - let recipient = starknet::contract_address_const::<0x5678>(); - let attestation_request = AttestationRequest { - schema, - data: AttestationRequestData { - recipient, expirationTime: 0, revocable: true, refUID: 0, data: array![], value: 0, - }, - }; - - let uid = dispatcher.attest(attestation_request); - assert_ne!(uid, 0, "Should return a non-zero UID"); - - let attestation = dispatcher.get_attestation(uid); - assert_eq!(attestation.schema, schema, "Should have correct schema"); - assert_eq!(attestation.recipient, recipient, "Should have correct recipient"); -} - -#[test] -fn test_revoke() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - // First, create an attestation - let schema = 0x1234_felt252; - let attestation_request = AttestationRequest { - schema, - data: AttestationRequestData { - recipient: starknet::contract_address_const::<0x5678>(), - expirationTime: 0, - revocable: true, - refUID: 0, - data: array![], - value: 0, - }, - }; - let uid = dispatcher.attest(attestation_request); - - // Now revoke it - let revocation_request = RevocationRequest { - schema, data: RevocationRequestData { uid, value: 0 }, - }; - dispatcher.revoke(revocation_request); - - let attestation = dispatcher.get_attestation(uid); - assert_ne!(attestation.revocation_time, 0, "Attestation should be revoked"); -} - -#[test] -fn test_timestamp() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - let data = 0x1234_felt252; - let timestamp = dispatcher.timestamp(data); - assert_ne!(timestamp, 0, "Should return a non-zero timestamp"); - - let stored_timestamp = dispatcher.get_timestamp(data); - assert_eq!(stored_timestamp, timestamp, "Stored timestamp should match"); -} - -#[test] -fn test_revoke_offchain() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - let data = 0x1234_felt252; - let timestamp = dispatcher.revoke_offchain(data); - assert_ne!(timestamp, 0, "Should return a non-zero timestamp"); - - let stored_timestamp = dispatcher.get_revoke_offchain(starknet::get_caller_address(), data); - assert_eq!(stored_timestamp, timestamp, "Stored revocation timestamp should match"); -} - -#[test] -fn test_attestation_validity() { - let registry_address = deploy_mock_schema_registry(); - let sas_address = deploy_sas(registry_address); - let dispatcher = ISASDispatcher { contract_address: sas_address }; - - let schema = 0x1234_felt252; - let attestation_request = AttestationRequest { - schema, - data: AttestationRequestData { - recipient: starknet::contract_address_const::<0x5678>(), - expirationTime: 0, - revocable: true, - refUID: 0, - data: array![], - value: 0, - }, - }; - let uid = dispatcher.attest(attestation_request); - - assert!(dispatcher.is_attestation_valid(uid), "Attestation should be valid"); - assert!(!dispatcher.is_attestation_valid(0), "Empty UID should be invalid"); -} -// Additional tests can be added for multi-attestation, delegation, and other complex scenarios +// use array::ArrayTrait; +// use option::OptionTrait; +// use serde::Serde; +// use snforge_std::ContractClassTrait; +// use traits::TryInto; + +// // Helper function to deploy the SAS contract +// fn deploy_sas(registry_address: ContractAddress) -> ContractAddress { +// let contract = declare("SAS"); +// let mut calldata = array![]; +// calldata.append_serde(registry_address); +// let (contract_address, _) = contract.deploy(@calldata).unwrap(); +// contract_address +// } + +// // Helper function to create a mock schema registry +// fn deploy_mock_schema_registry() -> ContractAddress { +// // Implement mock schema registry deployment +// // For now, we'll just return a dummy address +// starknet::contract_address_const::<0x1234>() +// } + +// #[test] +// fn test_sas_deployment() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// assert_eq!( +// dispatcher.get_schema_registry(), registry_address, "Should have correct schema registry" +// ); +// } + +// #[test] +// fn test_attest() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// let schema = 0x1234_felt252; +// let recipient = starknet::contract_address_const::<0x5678>(); +// let attestation_request = AttestationRequest { +// schema, +// data: AttestationRequestData { +// recipient, expirationTime: 0, revocable: true, refUID: 0, data: array![], value: 0, +// }, +// }; + +// let uid = dispatcher.attest(attestation_request); +// assert_ne!(uid, 0, "Should return a non-zero UID"); + +// let attestation = dispatcher.get_attestation(uid); +// assert_eq!(attestation.schema, schema, "Should have correct schema"); +// assert_eq!(attestation.recipient, recipient, "Should have correct recipient"); +// } + +// #[test] +// fn test_revoke() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// // First, create an attestation +// let schema = 0x1234_felt252; +// let attestation_request = AttestationRequest { +// schema, +// data: AttestationRequestData { +// recipient: starknet::contract_address_const::<0x5678>(), +// expirationTime: 0, +// revocable: true, +// refUID: 0, +// data: array![], +// value: 0, +// }, +// }; +// let uid = dispatcher.attest(attestation_request); + +// // Now revoke it +// let revocation_request = RevocationRequest { +// schema, data: RevocationRequestData { uid, value: 0 }, +// }; +// dispatcher.revoke(revocation_request); + +// let attestation = dispatcher.get_attestation(uid); +// assert_ne!(attestation.revocation_time, 0, "Attestation should be revoked"); +// } + +// #[test] +// fn test_timestamp() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// let data = 0x1234_felt252; +// let timestamp = dispatcher.timestamp(data); +// assert_ne!(timestamp, 0, "Should return a non-zero timestamp"); + +// let stored_timestamp = dispatcher.get_timestamp(data); +// assert_eq!(stored_timestamp, timestamp, "Stored timestamp should match"); +// } + +// #[test] +// fn test_revoke_offchain() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// let data = 0x1234_felt252; +// let timestamp = dispatcher.revoke_offchain(data); +// assert_ne!(timestamp, 0, "Should return a non-zero timestamp"); + +// let stored_timestamp = dispatcher.get_revoke_offchain(starknet::get_caller_address(), data); +// assert_eq!(stored_timestamp, timestamp, "Stored revocation timestamp should match"); +// } + +// #[test] +// fn test_attestation_validity() { +// let registry_address = deploy_mock_schema_registry(); +// let sas_address = deploy_sas(registry_address); +// let dispatcher = ISASDispatcher { contract_address: sas_address }; + +// let schema = 0x1234_felt252; +// let attestation_request = AttestationRequest { +// schema, +// data: AttestationRequestData { +// recipient: starknet::contract_address_const::<0x5678>(), +// expirationTime: 0, +// revocable: true, +// refUID: 0, +// data: array![], +// value: 0, +// }, +// }; +// let uid = dispatcher.attest(attestation_request); + +// assert!(dispatcher.is_attestation_valid(uid), "Attestation should be valid"); +// assert!(!dispatcher.is_attestation_valid(0), "Empty UID should be invalid"); +// } +// // Additional tests can be added for multi-attestation, delegation, and other complex scenarios From 438231e340927156838356bed652c6d44d6be3d3 Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 19:25:48 +0530 Subject: [PATCH 09/22] update code - linking SchemaRegistry and Attestation contract, revoke function --- SolasPresentation.md | 2 + .../nextjs/contracts/deployedContracts.ts | 232 +++++++++++++----- packages/nextjs/scaffold.config.ts | 2 +- .../contracts/src/AttestationRegistry.cairo | 116 ++++++--- packages/snfoundry/scripts-ts/deploy.ts | 4 +- 5 files changed, 246 insertions(+), 110 deletions(-) diff --git a/SolasPresentation.md b/SolasPresentation.md index 19c10ff..3deed6e 100644 --- a/SolasPresentation.md +++ b/SolasPresentation.md @@ -39,3 +39,5 @@ data: { - Ability to refer other attestations - Allow delegated attestations (Contract receives a signed attestation and attests onchain on behalf of user) +- Implement Revoke +- Implement option to refer an attestation diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index affdb5c..42ff57e 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -5,15 +5,14 @@ const deployedContracts = { devnet: { - AttestationRegistry: { + SchemaRegistry: { address: - "0x07c59f28a693a4d629f0b0358ae52649ca3e6743e111bedc0c822ee76ece3387", + "0x00417a5d2dc2fe77a06f1b7efe316e789cf9fbfb2630c502d9907ed16994af67", abi: [ { type: "impl", - name: "AttestationRegistryImpl", - interface_name: - "contracts::AttestationRegistry::IAttestationRegistry", + name: "SchemaRegistryImpl", + interface_name: "contracts::SchemaRegistry::ISchemaRegistry", }, { type: "struct", @@ -49,22 +48,14 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::AttestationRegistry::IAttestationRegistry", + name: "contracts::SchemaRegistry::ISchemaRegistry", items: [ { type: "function", - name: "attest", + name: "register", inputs: [ { - name: "schema_uid", - type: "core::integer::u128", - }, - { - name: "recipient", - type: "core::starknet::contract_address::ContractAddress", - }, - { - name: "data", + name: "schema", type: "core::byte_array::ByteArray", }, { @@ -79,69 +70,63 @@ const deployedContracts = { ], state_mutability: "external", }, - ], - }, - { - type: "constructor", - name: "constructor", - inputs: [ { - name: "schema_registry_address", - type: "core::starknet::contract_address::ContractAddress", + type: "function", + name: "get_schema", + inputs: [ + { + name: "uid", + type: "core::integer::u128", + }, + ], + outputs: [ + { + type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", + }, + ], + state_mutability: "view", }, ], }, { type: "event", - name: "contracts::AttestationRegistry::AttestationRegistry::Attested", + name: "contracts::SchemaRegistry::SchemaRegistry::Registered", kind: "struct", members: [ { - name: "recipient", - type: "core::starknet::contract_address::ContractAddress", + name: "uid", + type: "core::integer::u128", kind: "key", }, { - name: "attester", + name: "caller", type: "core::starknet::contract_address::ContractAddress", - kind: "key", - }, - { - name: "uid", - type: "core::integer::u128", kind: "data", }, { - name: "schema_uid", - type: "core::integer::u128", - kind: "key", - }, - { - name: "timestamp", - type: "core::integer::u64", + name: "schema_record", + type: "core::byte_array::ByteArray", kind: "data", }, ], }, { type: "event", - name: "contracts::AttestationRegistry::AttestationRegistry::Event", + name: "contracts::SchemaRegistry::SchemaRegistry::Event", kind: "enum", variants: [ { - name: "Attested", - type: "contracts::AttestationRegistry::AttestationRegistry::Attested", + name: "Registered", + type: "contracts::SchemaRegistry::SchemaRegistry::Registered", kind: "nested", }, ], }, ], }, - }, - sepolia: { - AttestationRegistry: { + AttestationRegistry: { address: - "0x077cf1b7bb4ce74559dbbab85714f1d69e520657670639ff77c9e99eedeb13f6", + "0x0415e94910dadd0a9be94dff4e5c762c4ccc034a66ebf424cb011ef885af0f41", abi: [ { type: "impl", @@ -213,6 +198,22 @@ const deployedContracts = { ], state_mutability: "external", }, + { + type: "function", + name: "revoke", + inputs: [ + { + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "attestation_uid", + type: "core::integer::u128", + }, + ], + outputs: [], + state_mutability: "external", + }, ], }, { @@ -257,6 +258,33 @@ const deployedContracts = { }, ], }, + { + type: "event", + name: "contracts::AttestationRegistry::AttestationRegistry::Revoked", + kind: "struct", + members: [ + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "attester", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "schema_uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "attestation_uid", + type: "core::integer::u128", + kind: "data", + }, + ], + }, { type: "event", name: "contracts::AttestationRegistry::AttestationRegistry::Event", @@ -267,18 +295,26 @@ const deployedContracts = { type: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "nested", }, + { + name: "Revoked", + type: "contracts::AttestationRegistry::AttestationRegistry::Revoked", + kind: "nested", + }, ], }, ], }, - SchemaRegistry: { + }, + sepolia: { + AttestationRegistry: { address: - "0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87", + "0x077cf1b7bb4ce74559dbbab85714f1d69e520657670639ff77c9e99eedeb13f6", abi: [ { type: "impl", - name: "SchemaRegistryImpl", - interface_name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "AttestationRegistryImpl", + interface_name: + "contracts::AttestationRegistry::IAttestationRegistry", }, { type: "struct", @@ -314,14 +350,22 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::SchemaRegistry::ISchemaRegistry", + name: "contracts::AttestationRegistry::IAttestationRegistry", items: [ { type: "function", - name: "register", + name: "attest", inputs: [ { - name: "schema", + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "data", type: "core::byte_array::ByteArray", }, { @@ -338,52 +382,104 @@ const deployedContracts = { }, { type: "function", - name: "get_schema", + name: "revoke", inputs: [ { - name: "uid", + name: "schema_uid", type: "core::integer::u128", }, - ], - outputs: [ { - type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", + name: "attestation_uid", + type: "core::integer::u128", }, ], - state_mutability: "view", + outputs: [], + state_mutability: "external", + }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [ + { + name: "schema_registry_address", + type: "core::starknet::contract_address::ContractAddress", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "contracts::AttestationRegistry::AttestationRegistry::Attested", kind: "struct", members: [ + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "attester", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, { name: "uid", type: "core::integer::u128", + kind: "data", + }, + { + name: "schema_uid", + type: "core::integer::u128", kind: "key", }, { - name: "caller", - type: "core::starknet::contract_address::ContractAddress", + name: "timestamp", + type: "core::integer::u64", kind: "data", }, + ], + }, + { + type: "event", + name: "contracts::AttestationRegistry::AttestationRegistry::Revoked", + kind: "struct", + members: [ { - name: "schema_record", - type: "core::byte_array::ByteArray", + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "attester", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "schema_uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "attestation_uid", + type: "core::integer::u128", kind: "data", }, ], }, { type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Event", + name: "contracts::AttestationRegistry::AttestationRegistry::Event", kind: "enum", variants: [ { - name: "Registered", - type: "contracts::SchemaRegistry::SchemaRegistry::Registered", + name: "Attested", + type: "contracts::AttestationRegistry::AttestationRegistry::Attested", + kind: "nested", + }, + { + name: "Revoked", + type: "contracts::AttestationRegistry::AttestationRegistry::Revoked", kind: "nested", }, ], diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index fac39e1..ee79a8f 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -9,7 +9,7 @@ export type ScaffoldConfig = { }; const scaffoldConfig = { - targetNetworks: [chains.sepolia], + targetNetworks: [chains.devnet], // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: process.env.NEXT_PUBLIC_PROVIDER_URL || "", diff --git a/packages/snfoundry/contracts/src/AttestationRegistry.cairo b/packages/snfoundry/contracts/src/AttestationRegistry.cairo index cccf497..b88e343 100644 --- a/packages/snfoundry/contracts/src/AttestationRegistry.cairo +++ b/packages/snfoundry/contracts/src/AttestationRegistry.cairo @@ -3,6 +3,7 @@ use super::SchemaRegistry::{ISchemaRegistry, ISchemaRegistryDispatcher}; #[starknet::interface] pub trait IAttestationRegistry { + // fn get_attestation(self: @TContractState, attestation_uid: u128) -> (u128, u128, u64, ContractAddress, ContractAddress, ByteArray, bool, u64); fn attest( ref self: TContractState, schema_uid: u128, @@ -10,41 +11,35 @@ pub trait IAttestationRegistry { data: ByteArray, revocable: bool ) -> u128; -// fn revoke(ref self: TContractState, request: RevocationRequest); + fn revoke(ref self: TContractState, schema_uid: u128, attestation_uid: u128); } // Define structs -#[derive(Drop, Serde, starknet::Store)] +#[derive(Drop, Serde, starknet::Store, Clone)] struct Attestation { uid: u128, schema_uid: u128, time: u64, - // expiration_time: u64, recipient: ContractAddress, attester: ContractAddress, data: ByteArray, + revocable: bool, + revocation_time: u64, } #[derive(Drop, Serde, starknet::Store)] struct AttestationRequest { schema_uid: u128, recipient: ContractAddress, - // expiration_time: u64, data: ByteArray, revocable: bool } -// #[derive(Drop, Serde, starknet::Store)] -// struct RevocationRequestData { -// uid: felt252, -// value: u256, -// } - -// #[derive(Drop, Serde, starknet::Store)] -// struct RevocationRequest { -// schema: felt252, -// data: RevocationRequestData, -// } +#[derive(Drop, Serde, starknet::Store)] +struct RevocationRequest { + schema_uid: u128, + attestation_uid: u128, +} #[starknet::contract] mod AttestationRegistry { @@ -58,16 +53,14 @@ mod AttestationRegistry { // Define constants const EMPTY_UID: u128 = 0; - const NO_EXPIRATION_TIME: u64 = 0; + const NO_TIME: u64 = 0; // Events #[event] #[derive(Drop, starknet::Event)] enum Event { Attested: Attested, - // Revoked: Revoked, - // Timestamped: Timestamped, - // RevokedOffchain: RevokedOffchain, + Revoked: Revoked, } #[derive(Drop, starknet::Event)] @@ -82,21 +75,22 @@ mod AttestationRegistry { timestamp: u64, } - // // The global mapping between attestations and their UIDs. - // mapping(bytes32 uid => Attestation attestation) private _db; - - // // The global mapping between data and their timestamps. - // mapping(bytes32 data => uint64 timestamp) private _timestamps; + #[derive(Drop, starknet::Event)] + struct Revoked { + #[key] + recipient: ContractAddress, + #[key] + attester: ContractAddress, + #[key] + schema_uid: u128, + attestation_uid: u128, + } - // // The global mapping between data and their revocation timestamps. - // mapping(address revoker => mapping(bytes32 data => uint64 timestamp) timestamps) private _revocationsOffchain; #[storage] struct Storage { schema_registry: ContractAddress, db: LegacyMap::, - timestamps: LegacyMap::, current_uid: u128, - // revocations_offchain: LegacyMap::<(ContractAddress, felt252), u64>, } // Constructor @@ -107,6 +101,11 @@ mod AttestationRegistry { #[abi(embed_v0)] impl AttestationRegistryImpl of IAttestationRegistry { + // fn get_attestation(self: @ContractState, attestation_uid: u128) -> (u128, u128, u64, ContractAddress, ContractAddress, ByteArray, bool, u64) { + // let data = self.db.read(attestation_uid); + // (data.uid, data.schema_uid, data.time, data.recipient, data.attester, data.data, data.revocable, data.revocation_time) + // } + fn attest( ref self: ContractState, schema_uid: u128, @@ -115,25 +114,26 @@ mod AttestationRegistry { revocable: bool ) -> u128 { let contract_address = self.schema_registry.read(); - // let (fetched_uid, fetched_revocable, fetched_schema) = ISchemaRegistryDispatcher { contract_address } - // .get_schema(schema_uid); + // check if schema exists + let (fetched_uid, fetched_revocable, _) = ISchemaRegistryDispatcher { contract_address } + .get_schema(schema_uid); - // assert!(fetched_uid != EMPTY_UID, "Schema Not Found"); - // assert!( - // request.expiration_time != NO_EXPIRATION_TIME - // && request.expiration_time <= get_block_timestamp(), - // "Invalid Expiration Time" - // ); - // assert!(!fetched_revocable && revocable, "Irrevocable"); + assert!(fetched_uid != EMPTY_UID, "Schema Not Found"); + + // check we are not trying to revoke an irrevocable schema + if (!fetched_revocable && revocable) { + panic!("Irrevocable"); + } let mut attestation = Attestation { uid: EMPTY_UID, schema_uid, time: get_block_timestamp(), - // expiration_time: request.expiration_time, recipient, attester: get_caller_address(), - data + data, + revocable: fetched_revocable, + revocation_time: 0, }; self.current_uid.write(self.current_uid.read() + 1); @@ -155,7 +155,43 @@ mod AttestationRegistry { uid } - // fn revoke(ref self: ContractState, request: RevocationRequest) {} + fn revoke(ref self: ContractState, schema_uid: u128, attestation_uid: u128) { + let contract_address = self.schema_registry.read(); + + // check if schema exists + let (fetched_schema_uid, _, _) = ISchemaRegistryDispatcher { contract_address } + .get_schema(schema_uid); + + assert!(fetched_schema_uid != EMPTY_UID, "Schema Not Found"); + + // check if attestation we are trying to revoke exists + let mut fetched_attestation = self.db.read(attestation_uid); + assert!(fetched_attestation.uid != EMPTY_UID, "Attestation Not Found"); + + // check we are not trying to revoke an irrevocable schema + assert!(fetched_attestation.revocable, "Irrevocable"); + + // ensure that we aren't trying to revoke the same attestation twice + assert!(fetched_attestation.revocation_time == NO_TIME, "Already Revoked"); + + let revoker = get_caller_address(); + // allow only original attesters to revoke their attestations + assert!(fetched_attestation.attester == revoker, "Access Denied"); + + fetched_attestation.revocation_time = get_block_timestamp(); + + self.db.write(attestation_uid, fetched_attestation.clone()); + + self + .emit( + Revoked { + recipient: fetched_attestation.recipient, + attester: revoker, + schema_uid, + attestation_uid, + } + ); + } } } diff --git a/packages/snfoundry/scripts-ts/deploy.ts b/packages/snfoundry/scripts-ts/deploy.ts index 93a2e8d..d345986 100644 --- a/packages/snfoundry/scripts-ts/deploy.ts +++ b/packages/snfoundry/scripts-ts/deploy.ts @@ -7,15 +7,17 @@ const deployScript = async (): Promise => { // }, // "SchemaRegistry", // ); + // 0x077cf1b7bb4ce74559dbbab85714f1d69e520657670639ff77c9e99eedeb13f6 await deployContract( { schema_registry_address: - "0x048ec8a62f68659ed94e57e497e154d96cc4d5356ef35a58c6b3f4e034325a8f", // the deployer address is the owner of the contract, + "0x00417a5d2dc2fe77a06f1b7efe316e789cf9fbfb2630c502d9907ed16994af67", // the deployer address is the owner of the contract, }, "AttestationRegistry" ); }; +// 0x03cdf276779fe3c83772cadc086b676c98bd602bcb8078c3736df49bb4003d0f // await deployContract( // { From b17895e4748dd9e1dacc471c691ccaf64e4bb568 Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 20:59:57 +0530 Subject: [PATCH 10/22] added get attestation function --- .../_components/contract/utilsDisplay.tsx | 3 +- .../nextjs/contracts/deployedContracts.ts | 112 +++++++++++++++++- .../contracts/src/AttestationRegistry.cairo | 21 +++- 3 files changed, 127 insertions(+), 9 deletions(-) diff --git a/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx b/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx index 15229f3..1a7762e 100644 --- a/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx +++ b/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx @@ -24,7 +24,7 @@ type DisplayContent = export const displayTxResult = ( displayContent: DisplayContent | DisplayContent[], asText: boolean, - functionOutputs: readonly AbiOutput[] = [], + functionOutputs: readonly AbiOutput[] = [] ): string | ReactElement | number => { if (displayContent == null) { return ""; @@ -32,6 +32,7 @@ export const displayTxResult = ( if (functionOutputs != null && functionOutputs.length != 0) { const type = functionOutputs[0].type; const parsedParam = parseParamWithType(type, displayContent, true); + console.log(parsedParam); if (typeof parsedParam === "bigint") { const asNumber = Number(parsedParam); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 42ff57e..4bee82d 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -124,9 +124,9 @@ const deployedContracts = { }, ], }, - AttestationRegistry: { + AttestationRegistry: { address: - "0x0415e94910dadd0a9be94dff4e5c762c4ccc034a66ebf424cb011ef885af0f41", + "0x043a0fcd4152f67425ca045f81babfdf9d8a0ed7a3e4dda1f1a5bfc094a8d5da", abi: [ { type: "impl", @@ -166,10 +166,64 @@ const deployedContracts = { }, ], }, + { + type: "struct", + name: "contracts::AttestationRegistry::Attestation", + members: [ + { + name: "uid", + type: "core::integer::u128", + }, + { + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "time", + type: "core::integer::u64", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "attester", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "data", + type: "core::byte_array::ByteArray", + }, + { + name: "revocable", + type: "core::bool", + }, + { + name: "revocation_time", + type: "core::integer::u64", + }, + ], + }, { type: "interface", name: "contracts::AttestationRegistry::IAttestationRegistry", items: [ + { + type: "function", + name: "get_attestation", + inputs: [ + { + name: "attestation_uid", + type: "core::integer::u128", + }, + ], + outputs: [ + { + type: "contracts::AttestationRegistry::Attestation", + }, + ], + state_mutability: "view", + }, { type: "function", name: "attest", @@ -348,10 +402,64 @@ const deployedContracts = { }, ], }, + { + type: "struct", + name: "contracts::AttestationRegistry::Attestation", + members: [ + { + name: "uid", + type: "core::integer::u128", + }, + { + name: "schema_uid", + type: "core::integer::u128", + }, + { + name: "time", + type: "core::integer::u64", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "attester", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "data", + type: "core::byte_array::ByteArray", + }, + { + name: "revocable", + type: "core::bool", + }, + { + name: "revocation_time", + type: "core::integer::u64", + }, + ], + }, { type: "interface", name: "contracts::AttestationRegistry::IAttestationRegistry", items: [ + { + type: "function", + name: "get_attestation", + inputs: [ + { + name: "attestation_uid", + type: "core::integer::u128", + }, + ], + outputs: [ + { + type: "contracts::AttestationRegistry::Attestation", + }, + ], + state_mutability: "view", + }, { type: "function", name: "attest", diff --git a/packages/snfoundry/contracts/src/AttestationRegistry.cairo b/packages/snfoundry/contracts/src/AttestationRegistry.cairo index b88e343..15bae40 100644 --- a/packages/snfoundry/contracts/src/AttestationRegistry.cairo +++ b/packages/snfoundry/contracts/src/AttestationRegistry.cairo @@ -3,7 +3,7 @@ use super::SchemaRegistry::{ISchemaRegistry, ISchemaRegistryDispatcher}; #[starknet::interface] pub trait IAttestationRegistry { - // fn get_attestation(self: @TContractState, attestation_uid: u128) -> (u128, u128, u64, ContractAddress, ContractAddress, ByteArray, bool, u64); + fn get_attestation(self: @TContractState, attestation_uid: u128) -> Attestation; fn attest( ref self: TContractState, schema_uid: u128, @@ -101,11 +101,20 @@ mod AttestationRegistry { #[abi(embed_v0)] impl AttestationRegistryImpl of IAttestationRegistry { - // fn get_attestation(self: @ContractState, attestation_uid: u128) -> (u128, u128, u64, ContractAddress, ContractAddress, ByteArray, bool, u64) { - // let data = self.db.read(attestation_uid); - // (data.uid, data.schema_uid, data.time, data.recipient, data.attester, data.data, data.revocable, data.revocation_time) - // } - + fn get_attestation(self: @ContractState, attestation_uid: u128) -> Attestation { + let data = self.db.read(attestation_uid); + Attestation { + uid: data.uid, + schema_uid: data.schema_uid, + time: data.time, + recipient: data.recipient, + attester: data.attester, + data: data.data, + revocable: data.revocable, + revocation_time: data.revocation_time, + } + } + fn attest( ref self: ContractState, schema_uid: u128, From e31189315b8499aa2b06a522296f43cd7ceae2ee Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Tue, 25 Jun 2024 18:47:57 +0300 Subject: [PATCH 11/22] add sepolia contracts --- .../nextjs/contracts/deployedContracts.ts | 121 +++++++++++++++++- packages/nextjs/scaffold.config.ts | 2 +- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 4bee82d..825a971 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -360,9 +360,128 @@ const deployedContracts = { }, }, sepolia: { + SchemaRegistry: { + address: + "0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87", + abi: [ + { + type: "impl", + name: "SchemaRegistryImpl", + interface_name: "contracts::SchemaRegistry::ISchemaRegistry", + }, + { + type: "struct", + name: "core::byte_array::ByteArray", + members: [ + { + name: "data", + type: "core::array::Array::", + }, + { + name: "pending_word", + type: "core::felt252", + }, + { + name: "pending_word_len", + type: "core::integer::u32", + }, + ], + }, + { + type: "enum", + name: "core::bool", + variants: [ + { + name: "False", + type: "()", + }, + { + name: "True", + type: "()", + }, + ], + }, + { + type: "interface", + name: "contracts::SchemaRegistry::ISchemaRegistry", + items: [ + { + type: "function", + name: "register", + inputs: [ + { + name: "schema", + type: "core::byte_array::ByteArray", + }, + { + name: "revocable", + type: "core::bool", + }, + ], + outputs: [ + { + type: "core::integer::u128", + }, + ], + state_mutability: "external", + }, + { + type: "function", + name: "get_schema", + inputs: [ + { + name: "uid", + type: "core::integer::u128", + }, + ], + outputs: [ + { + type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "event", + name: "contracts::SchemaRegistry::SchemaRegistry::Registered", + kind: "struct", + members: [ + { + name: "uid", + type: "core::integer::u128", + kind: "key", + }, + { + name: "caller", + type: "core::starknet::contract_address::ContractAddress", + kind: "data", + }, + { + name: "schema_record", + type: "core::byte_array::ByteArray", + kind: "data", + }, + ], + }, + { + type: "event", + name: "contracts::SchemaRegistry::SchemaRegistry::Event", + kind: "enum", + variants: [ + { + name: "Registered", + type: "contracts::SchemaRegistry::SchemaRegistry::Registered", + kind: "nested", + }, + ], + }, + ], + }, AttestationRegistry: { address: - "0x077cf1b7bb4ce74559dbbab85714f1d69e520657670639ff77c9e99eedeb13f6", + "0x034f38c70a7d4b1bab0b919c923545e74b188f95915b92b5febf12b0dafe6686", abi: [ { type: "impl", diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index ee79a8f..fac39e1 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -9,7 +9,7 @@ export type ScaffoldConfig = { }; const scaffoldConfig = { - targetNetworks: [chains.devnet], + targetNetworks: [chains.sepolia], // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: process.env.NEXT_PUBLIC_PROVIDER_URL || "", From 3f8a0b44bf1e088d14b4a1074523fa3f8fc16b21 Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Tue, 25 Jun 2024 21:24:15 +0530 Subject: [PATCH 12/22] deployed to Sepolia --- SolasPresentation.md | 5 + .../nextjs/contracts/deployedContracts.ts | 119 ------------------ packages/snfoundry/scripts-ts/deploy.ts | 2 +- 3 files changed, 6 insertions(+), 120 deletions(-) diff --git a/SolasPresentation.md b/SolasPresentation.md index 3deed6e..1e83227 100644 --- a/SolasPresentation.md +++ b/SolasPresentation.md @@ -41,3 +41,8 @@ data: { - Allow delegated attestations (Contract receives a signed attestation and attests onchain on behalf of user) - Implement Revoke - Implement option to refer an attestation + +## Sepolia Deployment Addresses + +SchemaRegistry: 0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87 +AttestationRegistry: 0x034f38c70a7d4b1bab0b919c923545e74b188f95915b92b5febf12b0dafe6686 diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 825a971..577e39b 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -5,125 +5,6 @@ const deployedContracts = { devnet: { - SchemaRegistry: { - address: - "0x00417a5d2dc2fe77a06f1b7efe316e789cf9fbfb2630c502d9907ed16994af67", - abi: [ - { - type: "impl", - name: "SchemaRegistryImpl", - interface_name: "contracts::SchemaRegistry::ISchemaRegistry", - }, - { - type: "struct", - name: "core::byte_array::ByteArray", - members: [ - { - name: "data", - type: "core::array::Array::", - }, - { - name: "pending_word", - type: "core::felt252", - }, - { - name: "pending_word_len", - type: "core::integer::u32", - }, - ], - }, - { - type: "enum", - name: "core::bool", - variants: [ - { - name: "False", - type: "()", - }, - { - name: "True", - type: "()", - }, - ], - }, - { - type: "interface", - name: "contracts::SchemaRegistry::ISchemaRegistry", - items: [ - { - type: "function", - name: "register", - inputs: [ - { - name: "schema", - type: "core::byte_array::ByteArray", - }, - { - name: "revocable", - type: "core::bool", - }, - ], - outputs: [ - { - type: "core::integer::u128", - }, - ], - state_mutability: "external", - }, - { - type: "function", - name: "get_schema", - inputs: [ - { - name: "uid", - type: "core::integer::u128", - }, - ], - outputs: [ - { - type: "(core::integer::u128, core::bool, core::byte_array::ByteArray)", - }, - ], - state_mutability: "view", - }, - ], - }, - { - type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Registered", - kind: "struct", - members: [ - { - name: "uid", - type: "core::integer::u128", - kind: "key", - }, - { - name: "caller", - type: "core::starknet::contract_address::ContractAddress", - kind: "data", - }, - { - name: "schema_record", - type: "core::byte_array::ByteArray", - kind: "data", - }, - ], - }, - { - type: "event", - name: "contracts::SchemaRegistry::SchemaRegistry::Event", - kind: "enum", - variants: [ - { - name: "Registered", - type: "contracts::SchemaRegistry::SchemaRegistry::Registered", - kind: "nested", - }, - ], - }, - ], - }, AttestationRegistry: { address: "0x043a0fcd4152f67425ca045f81babfdf9d8a0ed7a3e4dda1f1a5bfc094a8d5da", diff --git a/packages/snfoundry/scripts-ts/deploy.ts b/packages/snfoundry/scripts-ts/deploy.ts index d345986..3c1b355 100644 --- a/packages/snfoundry/scripts-ts/deploy.ts +++ b/packages/snfoundry/scripts-ts/deploy.ts @@ -12,7 +12,7 @@ const deployScript = async (): Promise => { await deployContract( { schema_registry_address: - "0x00417a5d2dc2fe77a06f1b7efe316e789cf9fbfb2630c502d9907ed16994af67", // the deployer address is the owner of the contract, + "0x067bdf6bf6f1b72315c541abdc443cdd55992ea29546933ddfec19cb200fce87", // the deployer address is the owner of the contract, }, "AttestationRegistry" ); From 775d29ecc179023f34887e0b831bd8f612be5bb0 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Tue, 25 Jun 2024 20:32:13 +0300 Subject: [PATCH 13/22] add attestation page --- .../app/dashboard/attestation/[uid]/page.tsx | 130 ++++++++++-------- .../app/dashboard/attestations/page.tsx | 20 +-- packages/nextjs/utils/utils.ts | 21 ++- 3 files changed, 91 insertions(+), 80 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx index 28bd520..b37bcec 100644 --- a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx +++ b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx @@ -1,32 +1,80 @@ "use client"; import React, { useState, useEffect } from "react"; import { useRouter, useSearchParams } from "next/navigation"; -import { fetchAttestation, Attestation } from "~~/utils/utils"; +import { Attestation, timeAgo } from "~~/utils/utils"; +import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; export default function AttestationPage({ params, }: { - params: { uid: string }; + params: { uid: number }; }) { const uid = params.uid; - const [attestation, setAttestation] = useState(null); + const [attestation, setAttestation] = useState(null); + + const { + data: fetchedAttestation, + isLoading, + isSuccess, + isError, + } = useScaffoldReadContract({ + contractName: "AttestationRegistry", + functionName: "get_attestation", + args: [uid], + watch: true, + enabled: true, + }); useEffect(() => { console.log("UUID:", uid); - if (uid) { - fetchAttestation(uid) - .then((data) => { - console.log("Fetched data:", data); - setAttestation(data); - }) - .catch((error) => { - console.error("Error fetching attestation:", error); - }); + console.log("Loading:", isLoading); + console.log("Success:", isSuccess); + console.log("Error:", isError); + console.log("Fetched Attestation:", fetchedAttestation); + + if (isSuccess && fetchedAttestation) { + // Check if fetchedAttestation is an object + const rawAttestation = fetchedAttestation as any; + const mappedAttestation: Attestation = { + attester: rawAttestation.attester.toString(), + data: { + data: rawAttestation.data.data.toString(), + }, + recipient: rawAttestation.recipient.toString(), + revocable: rawAttestation.revocable.toString(), + revocation_time: rawAttestation.revocation_time.toString(), + schema_uid: rawAttestation.schema_uid.toString(), + time: timeAgo(rawAttestation.time.toString()), + uid: rawAttestation.uid.toString(), + }; + console.log("Mapped Attestation:", mappedAttestation); + setAttestation(mappedAttestation); } - }, [uid]); + }, [isSuccess, isError, fetchedAttestation]); + if (isLoading) { + return ( +
+ +
+ ); + } if (!attestation) { - return
Loading...
; + return
No attestation data found.
; } return ( @@ -42,52 +90,26 @@ export default function AttestationPage({ - Schema - - - {attestation.schema} - - - - - Is Endorsement + Schema UID - {attestation.isEndorsement ? "True" : "False"} + {attestation.schema_uid} - Name + Is Revocable - {attestation.name} + {!!attestation.revocable ? "True" : "False"} - Domain + Data - {attestation.domain} - - - - - Context - - - {attestation.context} - - - - - IPFS Hash - - - - {attestation.ipfsHash} - + {attestation.data.data} @@ -95,7 +117,7 @@ export default function AttestationPage({ From - {attestation.from} + {attestation.attester} @@ -103,7 +125,7 @@ export default function AttestationPage({ To - {attestation.to} + {attestation.recipient} @@ -111,7 +133,7 @@ export default function AttestationPage({ Created - {attestation.created} + {attestation.time} @@ -119,15 +141,7 @@ export default function AttestationPage({ Expiration - {attestation.expiration} - - - - - Revoked - - - {attestation.revoked} + {attestation.revocation_time} diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 18d3477..f67139d 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -6,8 +6,8 @@ import Modal from "~~/components/Modal"; import CreateAttestationForm from "~~/components/forms/CreateAttestationForm"; const Attestations = () => { - const [totalSchemas, setTotalSchemas] = useState(0); - const [schemas, setSchemas] = useState([]); + const [totalAttestations, setTotalAttestations] = useState(0); + const [attestations, setAttestations] = useState([]); const { data: eventData, @@ -38,8 +38,8 @@ const Attestations = () => { useEffect(() => { if (eventData) { console.log(eventData); - setTotalSchemas(eventData.length); - setSchemas( + setTotalAttestations(eventData.length); + setAttestations( eventData.map((event) => ({ recipient: event.args.recipient, attester: event.args.attester, @@ -51,16 +51,16 @@ const Attestations = () => { } }, [eventData]); - const SchemaLink = ({ uid }: { uid: string }) => ( + const AttestationLink = ({ uid }: { uid: string }) => ( {uid.toString()} ); - const DashboardStats = ({ totalSchemas }: { totalSchemas: number }) => ( + const DashboardStats = ({ totalAttestations }: { totalAttestations: number }) => (
-
{totalSchemas}
+
{totalAttestations}
Total Schemas
@@ -93,7 +93,7 @@ const Attestations = () => {
- + {isLoading ? (
{ - {schemas.map((schema, index) => ( + {attestations.map((schema, index) => (
- + {schema.attester} diff --git a/packages/nextjs/utils/utils.ts b/packages/nextjs/utils/utils.ts index b130e75..74c8cbe 100644 --- a/packages/nextjs/utils/utils.ts +++ b/packages/nextjs/utils/utils.ts @@ -8,19 +8,16 @@ const contractAddress = const contract = new Contract(ERC20abi, contractAddress, provider); export type Attestation = { - uid: string; - schema: string; - isEndorsement: boolean; - name: string; - domain: string; - context: string; - ipfsHash: string; - from: string; - to: string; - created: string; - expiration: string; - revoked: string; + attester: any; + data: any + recipient: any; + revocable: any; + revocation_time: any; + schema_uid: any; + time: any; + uid: any; }; + export type Schema = { uid: string; schema: string; From 298bdfc1f6e07f2e32bdba5bd4e9ee9322b2f596 Mon Sep 17 00:00:00 2001 From: ShubhamChndrvnshi Date: Tue, 25 Jun 2024 23:02:32 +0530 Subject: [PATCH 14/22] vercel.json --- vercel.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..b8d4c51 --- /dev/null +++ b/vercel.json @@ -0,0 +1,16 @@ +{ + "version": 2, + "builds": [ + { + "src": "packages/nextjs/package.json", + "use": "@vercel/next" + } + ], + "routes": [ + { + "src": "/(.*)", + "dest": "packages/nextjs/$1" + } + ] +} + From a9b638ac2353d0fce7c44b8b4b19eabb0cbdaedd Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Tue, 25 Jun 2024 20:45:43 +0300 Subject: [PATCH 15/22] Update CreateAttestationForm.tsx --- .../nextjs/components/forms/CreateAttestationForm.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/components/forms/CreateAttestationForm.tsx b/packages/nextjs/components/forms/CreateAttestationForm.tsx index daeee3e..8a37fbc 100644 --- a/packages/nextjs/components/forms/CreateAttestationForm.tsx +++ b/packages/nextjs/components/forms/CreateAttestationForm.tsx @@ -15,19 +15,20 @@ const CreateAttestationForm = () => { useScaffoldWriteContract({ contractName: "AttestationRegistry", functionName: "attest", - args: [schema, recipient, data, revocable], + args: [15, recipient, data, false], }); const handleSubmit = async (formData: FormData) => { const revocableFetched = formData.get("revocable") as string; const recipient = formData.get("recipient") as string; const data = formData.get("data") as string; - - setSchema(0); + setRecipient(recipient); + setData(data); + setSchema(15); setRevocable(revocableFetched === "true"); try { await writeAsync({ - args: [schema, recipient, data, revocable], + args: [15, recipient, data, false], }); } catch (err) { console.error("Error submitting transaction:", err); From 99e8ba1ca2fe77f9e66d8cd5483186af1d03b97f Mon Sep 17 00:00:00 2001 From: ShubhamChndrvnshi Date: Tue, 25 Jun 2024 23:19:40 +0530 Subject: [PATCH 16/22] fix linting --- .../nextjs/app/dashboard/attestation/[uid]/page.tsx | 2 +- packages/nextjs/app/dashboard/attestations/page.tsx | 10 ++++++++-- .../app/debug/_components/contract/utilsDisplay.tsx | 2 +- packages/nextjs/utils/utils.ts | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx index b37bcec..092b2b1 100644 --- a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx +++ b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx @@ -44,7 +44,7 @@ export default function AttestationPage({ revocable: rawAttestation.revocable.toString(), revocation_time: rawAttestation.revocation_time.toString(), schema_uid: rawAttestation.schema_uid.toString(), - time: timeAgo(rawAttestation.time.toString()), + time: timeAgo(rawAttestation.time.toString()), uid: rawAttestation.uid.toString(), }; console.log("Mapped Attestation:", mappedAttestation); diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index f67139d..1e637af 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -57,10 +57,16 @@ const Attestations = () => { ); - const DashboardStats = ({ totalAttestations }: { totalAttestations: number }) => ( + const DashboardStats = ({ + totalAttestations, + }: { + totalAttestations: number; + }) => (
-
{totalAttestations}
+
+ {totalAttestations} +
Total Schemas
diff --git a/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx b/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx index 1a7762e..5e99dca 100644 --- a/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx +++ b/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx @@ -24,7 +24,7 @@ type DisplayContent = export const displayTxResult = ( displayContent: DisplayContent | DisplayContent[], asText: boolean, - functionOutputs: readonly AbiOutput[] = [] + functionOutputs: readonly AbiOutput[] = [], ): string | ReactElement | number => { if (displayContent == null) { return ""; diff --git a/packages/nextjs/utils/utils.ts b/packages/nextjs/utils/utils.ts index 74c8cbe..e1f51d8 100644 --- a/packages/nextjs/utils/utils.ts +++ b/packages/nextjs/utils/utils.ts @@ -9,7 +9,7 @@ const contract = new Contract(ERC20abi, contractAddress, provider); export type Attestation = { attester: any; - data: any + data: any; recipient: any; revocable: any; revocation_time: any; From 4a59c4c09c18b54b109d4f76ea4b3c15837e5260 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Wed, 26 Jun 2024 11:59:24 +0300 Subject: [PATCH 17/22] ui improvements and bug fixes --- .../app/dashboard/attestation/[uid]/page.tsx | 191 +++++++++--------- .../app/dashboard/attestations/page.tsx | 88 ++++---- packages/nextjs/app/dashboard/page.tsx | 34 +++- .../nextjs/app/dashboard/schemas/page.tsx | 23 ++- packages/nextjs/app/layout.tsx | 4 +- packages/nextjs/app/page.tsx | 2 +- packages/nextjs/components/Footer.tsx | 69 +------ packages/nextjs/components/Header.tsx | 38 ++-- .../forms/CreateAttestationForm.tsx | 11 +- packages/nextjs/public/solas.png | Bin 0 -> 1880 bytes 10 files changed, 211 insertions(+), 249 deletions(-) create mode 100644 packages/nextjs/public/solas.png diff --git a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx index 092b2b1..6c5415e 100644 --- a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx +++ b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx @@ -52,100 +52,105 @@ export default function AttestationPage({ } }, [isSuccess, isError, fetchedAttestation]); - if (isLoading) { - return ( -
- -
- ); - } - if (!attestation) { - return
No attestation data found.
; - } - return ( -
-
- UID: - - {attestation.uid} - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Schema UID - - {attestation.schema_uid} -
- Is Revocable - - {!!attestation.revocable ? "True" : "False"} -
- Data - - {attestation.data.data} -
- From - - {attestation.attester} -
- To - - {attestation.recipient} -
- Created - - {attestation.time} -
- Expiration - - {attestation.revocation_time} -
+
+
+
+ {isLoading || !attestation ? ( +
+ {" "} + +

+ Loading the attestation details... +

+
+ ) : ( +
+
+ UID: + + {attestation.uid} + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Schema UID + + {attestation.schema_uid} +
+ Is Revocable + + {!!attestation.revocable ? "True" : "False"} +
+ Data + + {attestation.data.data} +
+ From + + {attestation.attester} +
+ To + + {attestation.recipient} +
+ Created + + {attestation.time} +
+ Expiration + + {attestation.revocation_time} +
+
+
+ )} +
); diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 1e637af..3d5df74 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -46,7 +46,7 @@ const Attestations = () => { uid: event.args.uid, schema: event.args.schema_uid, timestamp: event.args.timestamp, - })), + })) ); } }, [eventData]); @@ -67,15 +67,15 @@ const Attestations = () => {
{totalAttestations}
-
Total Schemas
+
Total Attestations
); return (
-
-
+
+

@@ -101,7 +101,8 @@ const Attestations = () => {

{isLoading ? ( -
+
+ {" "} +

Loading all the attestations...

) : ( -
- - - - - - - - - - - - {attestations.map((schema, index) => ( - - - - - - +
+
+
UIDAttesterRecipientSchema UIDTimestamp
- - - {schema.attester} - - {schema.recipient} - - {schema.schema} - - {schema.timestamp} -
+ + + + + + + - ))} - -
UIDAttesterRecipientSchema UIDTimestamp
+ + + {attestations.map((schema, index) => ( + + + + + + {schema.attester} + + + {schema.recipient} + + + {schema.schema} + + + {schema.timestamp} + + + ))} + + +
+
)} -
diff --git a/packages/nextjs/app/dashboard/page.tsx b/packages/nextjs/app/dashboard/page.tsx index baa15a0..8b4a0d4 100644 --- a/packages/nextjs/app/dashboard/page.tsx +++ b/packages/nextjs/app/dashboard/page.tsx @@ -1,16 +1,36 @@ "use client"; import Link from "next/link"; import React, { useState, useEffect } from "react"; +import type { NextPage } from "next"; +import { Bars3Icon, BugAntIcon,CheckBadgeIcon,DocumentTextIcon,CodeBracketIcon } from "@heroicons/react/24/outline"; + const Dashboard = () => { return (
-
-

Welcome to Dashboard!

- Attestations -

-

- Schemas -
+
+
+
+ +

+ Tinker with your smart contract using the{" "} + + Make Attestations + {" "} + tab. +

+
+
+ +

+ Explore attestation and schemas via the{" "} + + Create Schemas + {" "} + tab. +

+
+
+
); }; diff --git a/packages/nextjs/app/dashboard/schemas/page.tsx b/packages/nextjs/app/dashboard/schemas/page.tsx index ab245e2..ead5b1f 100644 --- a/packages/nextjs/app/dashboard/schemas/page.tsx +++ b/packages/nextjs/app/dashboard/schemas/page.tsx @@ -54,8 +54,8 @@ const Schemas = () => { return (
-
-
+
+

@@ -81,7 +81,7 @@ const Schemas = () => {

{isLoading ? ( -
+
+

Loading all the schemas...

) : ( -
- +
+
+
@@ -124,13 +126,14 @@ const Schemas = () => { ))}
UID
+
+
)} -
diff --git a/packages/nextjs/app/layout.tsx b/packages/nextjs/app/layout.tsx index c14ec57..7ae991e 100644 --- a/packages/nextjs/app/layout.tsx +++ b/packages/nextjs/app/layout.tsx @@ -4,9 +4,9 @@ import "~~/styles/globals.css"; import { ThemeProvider } from "~~/components/ThemeProvider"; export const metadata: Metadata = { - title: "Scaffold-Stark", + title: "Solas", description: "Fast track your starknet journey", - icons: "/logo.ico", + icons: "/solas.png", }; const ScaffoldStarkApp = ({ children }: { children: React.ReactNode }) => { diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 06d7397..a1e8b30 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -15,7 +15,7 @@ const Home: NextPage = () => {

Welcome to - Scaffold-Stark 2 + Solas

Connected Address:

diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index 321f72f..f55e550 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -25,88 +25,25 @@ export const Footer = () => { const isLocalNetwork = targetNetwork.id === devnet.id; return ( -
+
-
-
- {nativeCurrencyPrice > 0 && ( -
-
- - {nativeCurrencyPrice} -
-
- )} - {isLocalNetwork && ( - <> - - - - Block Explorer - - - )} -
-
    diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx index aac3b17..967094f 100644 --- a/packages/nextjs/components/Header.tsx +++ b/packages/nextjs/components/Header.tsx @@ -4,7 +4,7 @@ import React, { useCallback, useRef, useState } from "react"; import Image from "next/image"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { Bars3Icon, BugAntIcon } from "@heroicons/react/24/outline"; +import { Bars3Icon, BugAntIcon,CheckBadgeIcon,DocumentTextIcon,CodeBracketIcon } from "@heroicons/react/24/outline"; import { useOutsideClick } from "~~/hooks/scaffold-stark"; import { CustomConnectButton } from "~~/components/scaffold-stark/CustomConnectButton"; import { FaucetButton } from "~~/components/scaffold-stark/FaucetButton"; @@ -18,12 +18,22 @@ type HeaderMenuLink = { export const menuLinks: HeaderMenuLink[] = [ { label: "Home", - href: "/", + href: "/dashboard", }, { - label: "Debug Contracts", + label: "Attestations", + href: "/dashboard/attestations", + icon: , + }, + { + label: "Schemas", + href: "/dashboard/schemas", + icon: , + }, + { + label: "Contracts", href: "/debug", - icon: , + icon: , }, ]; @@ -65,7 +75,7 @@ export const Header = () => { ); return ( -
    +
)}
- -
- SE2 logo -
-
- Scaffold-Stark - Starknet dev stack -
-
diff --git a/packages/nextjs/components/forms/CreateAttestationForm.tsx b/packages/nextjs/components/forms/CreateAttestationForm.tsx index 8a37fbc..b0a3ea0 100644 --- a/packages/nextjs/components/forms/CreateAttestationForm.tsx +++ b/packages/nextjs/components/forms/CreateAttestationForm.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/navigation"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; const CreateAttestationForm = () => { - const [schema, setSchema] = useState(0); + const [schema, setSchema] = useState(15); const [recipient, setRecipient] = useState(""); const [data, setData] = useState(""); @@ -15,20 +15,21 @@ const CreateAttestationForm = () => { useScaffoldWriteContract({ contractName: "AttestationRegistry", functionName: "attest", - args: [15, recipient, data, false], + args: [schema as number, recipient, data, false], }); const handleSubmit = async (formData: FormData) => { const revocableFetched = formData.get("revocable") as string; const recipient = formData.get("recipient") as string; const data = formData.get("data") as string; + const fetchedSchema = formData.get("schema") as string; + setSchema(parseInt(fetchedSchema)); + setRevocable(false); setRecipient(recipient); setData(data); - setSchema(15); - setRevocable(revocableFetched === "true"); try { await writeAsync({ - args: [15, recipient, data, false], + args: [schema, recipient, data, false], }); } catch (err) { console.error("Error submitting transaction:", err); diff --git a/packages/nextjs/public/solas.png b/packages/nextjs/public/solas.png new file mode 100644 index 0000000000000000000000000000000000000000..410457342a5c0878fe6ed4070b81e215a98d1e23 GIT binary patch literal 1880 zcmV-e2dDUnP)88#TRM~VJ*mW1PXbagCHqfL=5KjO+LEs5Oo&Y&H&A)ScAR9>AMVu#y zyYD$w-@sjzxQ(Uhy|M)+mTlQ{N0!O&oPezeBR+jIbLY+-Axwd)cTkyYe^zx+xmv*u z1f18PD+*MFzbEI>@n!^3lU@e=4(FdelGdLa}IQj8-N4IAg)M`Jtl@=%otKGCAxLip5me zX>sg01|uDI3Hq#21n=>5A?xTl)M1~1Sd4pBe}0hl67peWe^yF6*p1@z zLBm^6`iMs0MhhsDT1&rJ9;qV;=P^DOZT36s8r@oa1z)- zbXOjo!s-4bbGx_&L~55lXanRK8lUwEMiXjoiY{2dRH%=!CmhyKYHN$B|8wC2EV_%t zIy%LFHf=0kEPKzlDRKD_1nJH<>mMJ#5LS>_4?vi%t9FiSYpb?adQSWw_7QObI;%?} zpmtKVICGdKcLnr^tRDMo4afm*qDnjOq^59bE<1OaLg@}PPNU={787^W2#X*@n#*Fr z;?7fc;lemkH!1NAqAmbL&{bZq=snVLSO`@Rgqz_s#7cF^PlGvAw?RXpVo9934K zK$KN^U&3W7Jn!FC6ow)zKXhUKH2bYIq+F&{>8x2Q>Yzmg`+y%L>@N(bpO8Nb%yTQG!j-&;j7}r`g8#V%~XvD^=gr98VsvSCh9F zCf^#vJ&>VN(xt<3Hw~Czt3acV!B;odu92)?!>0fT zskL=)*eN4djgB9$ZA;|KW`KZ#RBzNtnU>jT)ZBziyuuytp34|uXA+D*h%2KdQb0u{ z!Z35ycjkrMPW?M9UN+Il2%BkpiUu*($~TKfcVp+Wh{j^k-{g<=GcW*Ha1UPNOMB3MFq5rms6_irv(BJQJfRHK~Pku9Ole^*Y#ecbs&I$SWMBa(haZmPFn zvJCEIzjq3pIWOXkVf=5z<6_PqFVg^}8wjdCtxc>`5o{1~IvUCs28*I?Df}N5GZfB8 S+be+p0000 Date: Wed, 26 Jun 2024 12:15:29 +0300 Subject: [PATCH 18/22] minor fix --- packages/nextjs/app/dashboard/attestations/page.tsx | 9 +++++---- packages/nextjs/app/dashboard/schemas/page.tsx | 3 ++- packages/nextjs/utils/utils.ts | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 3d5df74..9e9b18f 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import Modal from "~~/components/Modal"; import CreateAttestationForm from "~~/components/forms/CreateAttestationForm"; +import { shortAddress, timeAgo } from "~~/utils/utils"; const Attestations = () => { const [totalAttestations, setTotalAttestations] = useState(0); @@ -41,11 +42,11 @@ const Attestations = () => { setTotalAttestations(eventData.length); setAttestations( eventData.map((event) => ({ - recipient: event.args.recipient, - attester: event.args.attester, + recipient: shortAddress(event.args.recipient), + attester: shortAddress(event.args.attester), uid: event.args.uid, - schema: event.args.schema_uid, - timestamp: event.args.timestamp, + schema: (event.args.schema_uid).toString(), + timestamp: timeAgo((event.args.timestamp).toString()), })) ); } diff --git a/packages/nextjs/app/dashboard/schemas/page.tsx b/packages/nextjs/app/dashboard/schemas/page.tsx index ead5b1f..e1fdb15 100644 --- a/packages/nextjs/app/dashboard/schemas/page.tsx +++ b/packages/nextjs/app/dashboard/schemas/page.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import Modal from "~~/components/Modal"; import RegisterSchemaForm from "~~/components/forms/RegisterSchemaForm"; +import { shortAddress } from "~~/utils/utils"; const Schemas = () => { const [totalSchemas, setTotalSchemas] = useState(0); @@ -31,7 +32,7 @@ const Schemas = () => { eventData.map((event) => ({ uid: event.args.uid, schema: event.args.schema_record, - caller: event.args.caller, + caller:shortAddress(event.args.caller), })), ); } diff --git a/packages/nextjs/utils/utils.ts b/packages/nextjs/utils/utils.ts index e1f51d8..3c50096 100644 --- a/packages/nextjs/utils/utils.ts +++ b/packages/nextjs/utils/utils.ts @@ -131,11 +131,11 @@ export const shortAddress = (addr: string): string => { return ""; } return ( - addr.toString().substring(0, 6) + + addr.toString().substring(0, 8) + "..." + addr .toString() - .substring(addr.toString().length - 6, addr.toString().length + 1) + .substring(addr.toString().length - 8, addr.toString().length + 1) ); }; From 3aef170d7aeca041ee86271058e9889d5d115291 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Wed, 26 Jun 2024 15:51:08 +0300 Subject: [PATCH 19/22] ui changes --- packages/nextjs/app/dashboard/page.tsx | 8 ++-- packages/nextjs/app/layout.tsx | 2 +- packages/nextjs/app/page.tsx | 65 ++------------------------ packages/nextjs/components/Header.tsx | 17 +++++-- 4 files changed, 20 insertions(+), 72 deletions(-) diff --git a/packages/nextjs/app/dashboard/page.tsx b/packages/nextjs/app/dashboard/page.tsx index 8b4a0d4..a09e2fb 100644 --- a/packages/nextjs/app/dashboard/page.tsx +++ b/packages/nextjs/app/dashboard/page.tsx @@ -12,9 +12,9 @@ const Dashboard = () => {

- Tinker with your smart contract using the{" "} + Start making attestations on existing schemas using the{" "} - Make Attestations + Attestations {" "} tab.

@@ -22,9 +22,9 @@ const Dashboard = () => {

- Explore attestation and schemas via the{" "} + Explore the schemas or create a new schema using the{" "} - Create Schemas + Schemas {" "} tab.

diff --git a/packages/nextjs/app/layout.tsx b/packages/nextjs/app/layout.tsx index 7ae991e..b71bf2d 100644 --- a/packages/nextjs/app/layout.tsx +++ b/packages/nextjs/app/layout.tsx @@ -12,7 +12,7 @@ export const metadata: Metadata = { const ScaffoldStarkApp = ({ children }: { children: React.ReactNode }) => { return ( - + {children} diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index a1e8b30..9952ef6 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -6,73 +6,14 @@ import { BugAntIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { Address } from "~~/components/scaffold-stark"; import { useAccount } from "@starknet-react/core"; import { Address as AddressType } from "@starknet-react/chains"; - +import Dashboard from "./dashboard/page"; const Home: NextPage = () => { const connectedAddress = useAccount(); return ( <> -
-
-

- Welcome to - Solas -

-
-

Connected Address:

-
-
-

- Get started by editing{" "} - - packages/nextjs/app/page.tsx - -

-

- Edit your smart contract{" "} - - YourContract.cairo - {" "} - in{" "} - - packages/snfoundry/contracts/src - -

-
- -
-
-
- -

- Tinker with your smart contract using the{" "} - - Debug Contracts - {" "} - tab. -

-
-
- -

- Explore attestation and schemas via the{" "} - - Dashboard - {" "} - tab. -

-
-
-
- {/*
{ - writeAsync(); - }} - > - TEST TX -
*/} -
+ ); }; -export default Home; +export default Home; \ No newline at end of file diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx index 967094f..eb7d524 100644 --- a/packages/nextjs/components/Header.tsx +++ b/packages/nextjs/components/Header.tsx @@ -4,7 +4,13 @@ import React, { useCallback, useRef, useState } from "react"; import Image from "next/image"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { Bars3Icon, BugAntIcon,CheckBadgeIcon,DocumentTextIcon,CodeBracketIcon } from "@heroicons/react/24/outline"; +import { + Bars3Icon, + BugAntIcon, + CheckBadgeIcon, + DocumentTextIcon, + CodeBracketIcon, +} from "@heroicons/react/24/outline"; import { useOutsideClick } from "~~/hooks/scaffold-stark"; import { CustomConnectButton } from "~~/components/scaffold-stark/CustomConnectButton"; import { FaucetButton } from "~~/components/scaffold-stark/FaucetButton"; @@ -50,8 +56,10 @@ export const HeaderMenuLinks = () => { href={href} passHref className={`${ - isActive ? "bg-secondary shadow-md" : "" - } hover:bg-secondary hover:shadow-md focus:!bg-secondary active:!text-neutral py-1.5 px-3 text-sm rounded-full gap-2 grid grid-flow-col`} + isActive + ? "bg-[#E9E9F6] shadow-md text-[#475299]" + : "text-[#E9E9F6]" + } hover:bg-[#E9E9F6] hover:shadow-md hover:text-[#475299] focus:bg-[#E9E9F6] focus:text-[#475299] active:bg-[#E9E9F6] active:text-[#475299] py-1.5 px-3 text-sm rounded-full gap-2 grid grid-flow-col`} > {icon} {label} @@ -71,9 +79,8 @@ export const Header = () => { const burgerMenuRef = useRef(null); useOutsideClick( burgerMenuRef, - useCallback(() => setIsDrawerOpen(false), []), + useCallback(() => setIsDrawerOpen(false), []) ); - return (
From aaddb38fe63fbb2a6de2dd3c879a7c1dbe141934 Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Wed, 26 Jun 2024 16:02:50 +0300 Subject: [PATCH 20/22] formatting --- .next/trace | 1 + .../app/dashboard/attestation/[uid]/page.tsx | 6 -- .../app/dashboard/attestations/page.tsx | 6 +- packages/nextjs/app/dashboard/page.tsx | 44 +++++++------ .../nextjs/app/dashboard/schemas/page.tsx | 64 ++++++++++--------- packages/nextjs/app/page.tsx | 4 +- packages/nextjs/components/Footer.tsx | 21 ++---- packages/nextjs/components/Header.tsx | 2 +- packages/nextjs/utils/utils.ts | 19 ------ 9 files changed, 71 insertions(+), 96 deletions(-) create mode 100644 .next/trace diff --git a/.next/trace b/.next/trace new file mode 100644 index 0000000..adaa564 --- /dev/null +++ b/.next/trace @@ -0,0 +1 @@ +[{"name":"generate-buildid","duration":151,"timestamp":196797712252,"id":4,"parentId":1,"tags":{},"startTime":1719406393678,"traceId":"647503704223d41d"},{"name":"load-custom-routes","duration":136,"timestamp":196797712508,"id":5,"parentId":1,"tags":{},"startTime":1719406393678,"traceId":"647503704223d41d"},{"name":"next-build","duration":60165,"timestamp":196797653648,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"14.2.4","isTurbopack":false},"startTime":1719406393619,"traceId":"647503704223d41d"}] diff --git a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx index 6c5415e..6698f65 100644 --- a/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx +++ b/packages/nextjs/app/dashboard/attestation/[uid]/page.tsx @@ -26,12 +26,6 @@ export default function AttestationPage({ }); useEffect(() => { - console.log("UUID:", uid); - console.log("Loading:", isLoading); - console.log("Success:", isSuccess); - console.log("Error:", isError); - console.log("Fetched Attestation:", fetchedAttestation); - if (isSuccess && fetchedAttestation) { // Check if fetchedAttestation is an object const rawAttestation = fetchedAttestation as any; diff --git a/packages/nextjs/app/dashboard/attestations/page.tsx b/packages/nextjs/app/dashboard/attestations/page.tsx index 9e9b18f..15663d9 100644 --- a/packages/nextjs/app/dashboard/attestations/page.tsx +++ b/packages/nextjs/app/dashboard/attestations/page.tsx @@ -45,9 +45,9 @@ const Attestations = () => { recipient: shortAddress(event.args.recipient), attester: shortAddress(event.args.attester), uid: event.args.uid, - schema: (event.args.schema_uid).toString(), - timestamp: timeAgo((event.args.timestamp).toString()), - })) + schema: event.args.schema_uid.toString(), + timestamp: timeAgo(event.args.timestamp.toString()), + })), ); } }, [eventData]); diff --git a/packages/nextjs/app/dashboard/page.tsx b/packages/nextjs/app/dashboard/page.tsx index a09e2fb..f2e49d3 100644 --- a/packages/nextjs/app/dashboard/page.tsx +++ b/packages/nextjs/app/dashboard/page.tsx @@ -2,35 +2,41 @@ import Link from "next/link"; import React, { useState, useEffect } from "react"; import type { NextPage } from "next"; -import { Bars3Icon, BugAntIcon,CheckBadgeIcon,DocumentTextIcon,CodeBracketIcon } from "@heroicons/react/24/outline"; +import { + Bars3Icon, + BugAntIcon, + CheckBadgeIcon, + DocumentTextIcon, + CodeBracketIcon, +} from "@heroicons/react/24/outline"; const Dashboard = () => { return (
-
-
- -

+

+
+ +

Start making attestations on existing schemas using the{" "} - - Attestations - {" "} - tab. -

-
-
- -

+ + Attestations + {" "} + tab. +

+
+
+ +

Explore the schemas or create a new schema using the{" "} - + Schemas - {" "} - tab. -

-
+ {" "} + tab. +

+
); }; diff --git a/packages/nextjs/app/dashboard/schemas/page.tsx b/packages/nextjs/app/dashboard/schemas/page.tsx index e1fdb15..19f4eeb 100644 --- a/packages/nextjs/app/dashboard/schemas/page.tsx +++ b/packages/nextjs/app/dashboard/schemas/page.tsx @@ -32,7 +32,7 @@ const Schemas = () => { eventData.map((event) => ({ uid: event.args.uid, schema: event.args.schema_record, - caller:shortAddress(event.args.caller), + caller: shortAddress(event.args.caller), })), ); } @@ -102,38 +102,40 @@ const Schemas = () => {
) : (
-
- - - - - - - - - - {schemas.map((schema, index) => ( - - - - +
+
UIDCreatorSchema Record
- - - {schema.caller} - - {schema.schema} -
+ + + + + - ))} - -
UIDCreator + Schema Record +
- + + + {schemas.map((schema, index) => ( + + + + + + {schema.caller} + + + {schema.schema} + + + ))} + + +
+
-
)}
diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 9952ef6..3af8f57 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -11,9 +11,9 @@ const Home: NextPage = () => { const connectedAddress = useAccount(); return ( <> - + ); }; -export default Home; \ No newline at end of file +export default Home; diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index f55e550..db92061 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -27,25 +27,16 @@ export const Footer = () => { return (
- +
diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx index eb7d524..a2d20e2 100644 --- a/packages/nextjs/components/Header.tsx +++ b/packages/nextjs/components/Header.tsx @@ -79,7 +79,7 @@ export const Header = () => { const burgerMenuRef = useRef(null); useOutsideClick( burgerMenuRef, - useCallback(() => setIsDrawerOpen(false), []) + useCallback(() => setIsDrawerOpen(false), []), ); return (
diff --git a/packages/nextjs/utils/utils.ts b/packages/nextjs/utils/utils.ts index 3c50096..a10a352 100644 --- a/packages/nextjs/utils/utils.ts +++ b/packages/nextjs/utils/utils.ts @@ -86,25 +86,6 @@ export const fetchAllAttestations = async () => { ]; }; -// Dummy fetch function to simulate fetching attestation data -export const fetchAttestation = async (uuid: string): Promise => { - // Replace this with your actual fetch call to get attestation data - return { - uid: uuid, - schema: "#159", - isEndorsement: true, - name: "Worked with", - domain: "via 0x794ce...", - context: "via 0x794ce...", - ipfsHash: "ipfs://QmZaTm...Jx3ziBQnPS", - from: "0x07a059F968efF2D70973Ed90abfb5B93DD6050198888792b5EAE5798BdE677E", - to: "0xd34d059F968efF2D70973Ed90abfb5B93DD6050198888792b5EAE5798BdE677E", - created: "06/22/2024 3:13:21 am", - expiration: "Never", - revoked: "No", - }; -}; - export const fetchTokenName = async (): Promise => { try { const name = await contract.call("name"); From 3dbe057903b98462a4b23e5738b1dc15de5296ee Mon Sep 17 00:00:00 2001 From: Rojhat Toptamus Date: Wed, 26 Jun 2024 16:06:07 +0300 Subject: [PATCH 21/22] Update Footer.tsx --- packages/nextjs/components/Footer.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index db92061..e810159 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -35,9 +35,7 @@ export const Footer = () => {
    -
    - -
    +
From ec5ef62af767a75c3703627b1c9a6359b0aad64a Mon Sep 17 00:00:00 2001 From: Suraj Kohli Date: Wed, 26 Jun 2024 18:43:45 +0530 Subject: [PATCH 22/22] remove vercel.json from root --- vercel.json | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 vercel.json diff --git a/vercel.json b/vercel.json deleted file mode 100644 index b8d4c51..0000000 --- a/vercel.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": 2, - "builds": [ - { - "src": "packages/nextjs/package.json", - "use": "@vercel/next" - } - ], - "routes": [ - { - "src": "/(.*)", - "dest": "packages/nextjs/$1" - } - ] -} -