ethereum-attestation-service / eas-sdk Goto Github PK
View Code? Open in Web Editor NEWEthereum Attestation Service - TypeScript/JavaScript SDK
License: MIT License
Ethereum Attestation Service - TypeScript/JavaScript SDK
License: MIT License
Hi
I started working on an alternative frontend which uses this SDK with wagmi/viem. The frontend is part of Avalanche deployment of EAS which is being led by @cryptofish7: https://github.com/avax-attestations/aas-frontend
In the docs I found a link to a gist with some hooks which wrapped wagmi/viem clients in ethers compatible signer/provider, but the code was outdated (it was targeting ethers v5) so I had to adapt it. Here's the updated code which works with ethers v6:
// useProvider.ts
import { JsonRpcProvider, FallbackProvider } from "ethers";
import { type PublicClient } from "viem";
import { useState, useEffect } from "react";
import { usePublicClient } from "wagmi";
function publicClientToProvider(publicClient: PublicClient) {
const { chain, transport } = publicClient;
if (!chain) {
return;
}
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address
};
if (transport.type === "fallback") {
return new FallbackProvider(
(transport.transports).map(
({ value }: any) => new JsonRpcProvider(value?.url, network)
)
);
}
return new JsonRpcProvider(transport.url, network);
}
type Provider = ReturnType<typeof publicClientToProvider>
export function useProvider() {
const publicClient = usePublicClient();
const [provider, setProvider] = useState<Provider | undefined>(undefined);
useEffect(() => {
if (publicClient) {
setProvider(publicClientToProvider(publicClient));
}
}, [publicClient]);
return provider;
}
// useSigner.ts
import { useEffect, useState } from "react";
import { useWalletClient } from "wagmi";
import { type WalletClient } from "viem";
import { BrowserProvider, JsonRpcSigner } from "ethers";
export async function walletClientToSigner(walletClient: WalletClient) {
const { account, chain, transport } = walletClient;
if (!chain || !account) {
return;
}
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address
};
const provider = new BrowserProvider(transport, network);
const signer = await provider.getSigner(account.address);
return signer;
}
export function useSigner() {
const { data: walletClient } = useWalletClient();
const [signer, setSigner] = useState<JsonRpcSigner | undefined>(undefined);
useEffect(() => {
if (walletClient) {
walletClientToSigner(walletClient).then((signer) => {
setSigner(signer);
})
}
}, [walletClient]);
return signer;
}
If you want, I can create a PR that adds these hooks to a new module (wagmi-compat.ts) so that this functionality is more easily available to SDK users. The module would not be referenced by other modules in this package and users would have to import it directly with something like:
import { useSigner, useProvider } from "@ethereum-attestation-service/eas-sdk/wagmi-compat"
I would also add viem
, wagmi
and react
as peer dependencies.
I don't know, why revoking off-chain attestation needs to interact with the EAS contract.
Writing to contract will cost gas. it's unfriendly to off-chain operations.
Hi,
I am currently trying to verify an offchain attestation by following the provided example from the readme.
Unfortunately the code snippet seems irrelevant (or am I missing something?).
Thank you for the clarification/fix.
Edit: the same example from the documentation seems to exhibit even more issues.
This simple code doesn't work with ethers v6.7.1 and typescript v5.2.2:
ethers.ts
import { JsonRpcProvider } from 'ethers'
export const provider = new JsonRpcProvider(process.env.RPC_PROVIDER)
eas.ts
import { EAS } from '@ethereum-attestation-service/eas-sdk'
import { provider } from './ethers.js'
export const eas = new EAS(process.env.EAS_CONTRACT)
eas.connect(provider)
Argument of type 'JsonRpcProvider' is not assignable to parameter of type 'SignerOrProvider'.
Type 'JsonRpcProvider' is not assignable to type 'Provider'.
The types returned by 'getNetwork()' are incompatible between these types.
Type 'Promise<import("d:/Desktop/Hackathons/Newforum/EAS/node_modules/ethers/lib.esm/providers/network", { assert: { "resolution-mode": "import" } }).Network>' is not assignable to type 'Promise<import("d:/Desktop/Hackathons/Newforum/EAS/node_modules/ethers/lib.commonjs/providers/network").Network>'.
Type 'import("d:/Desktop/Hackathons/Newforum/EAS/node_modules/ethers/lib.esm/providers/network", { assert: { "resolution-mode": "import" } }).Network' is not assignable to type 'import("d:/Desktop/Hackathons/Newforum/EAS/node_modules/ethers/lib.commonjs/providers/network").Network'.
Property '#private' in type 'Network' refers to a different member that cannot be accessed from within type 'Network'.ts(2345)
I understand that we need to inject a provider for legacy version detection when calling eas.getOffchain
but the documentation is not made clear for this which causes the "provider wasn't set" error when people try to replicate the example.
Lines 157 to 159 in 939a12a
From my opinion, there should be a better resolution for the provider. How about splitting signer and provider?
Where can I review the code for your private data attestations?
In the docs you outline how to create private data attestations.
If the data space size is low, the attestation can be easily guessed.
For example a schema of
Name, Gender, over100k, credit score
Assuming the verifier knows his customer name, he can easily iterate through the possible values and guess the merkle root as there are only
2(gender)*2(over100k)*1000 different options.
To make it resistant each data needs to be paired with a random nonce node. (can be made deterministic for example by using the hash of the signed value by the recipient private key)
Hi, I'm in a situation where I have to create off-chain attestation that references an on-chain attestation.
Also, my schema resolver logic requires validating the attestation provided in refUID.
Due to the fix in this PR: #54, which set the refUID to be zero bytes 32 all the time, my resolver logic fails.
eas-sdk/src/offchain/offchain.ts
Lines 217 to 220 in ef088c1
My question: could we allow simulating resolver with refUID: params.refUID || ZERO_BYTES32
?
We are ready to make off-chain attestation and publish it to query after.
But the SDK is just for making, how to publish it by EAS-SDK, and then display on the EAS platform.
Or some other suggestions for me.
Attest
Hi, I would like to know how we can use the private data attestation especially when it comes to validating if the given inputs match the output proof for the verifiers.
I came across this question after reading this part of the document: https://docs.attest.sh/docs/tutorials/private-data-attestations
For example, I was able to generate the following Proof Result from parts of the private data on the attestation:
{"leaves":[{"type":"string","name":"date_of_birth","value":"1997/1/1","salt":"0x69e42ffc6776c137dc9b3f55d129cb8ade03f246e2ed9ace36e9b5a65ea6c8e4"}],"proof":["0x5642f8152e7460dfd8917be8a736e4af0cbb34fd25daa1e4c03a315eec6854df"],"proofFlags":[false]}
Link to the attestation: https://sepolia.easscan.org/attestation/view/0x9035ad04e14aecf266c9353601e1e6821ef53f3327df03afcb222c91186205b8
Let's say I give this information to someone, how can that person validate if the leaves can produce the proof exactly?
It will be good if you can share the code reference of where this can be found.
Thank you.
The transactional methods such as attest
or register
exposed by EAS SDK should accept options (ethers Override) for on-chain transactions.
We need to customize:
I see on EASScan that offchain attestations are added to IPFS (and pinned presumably). Are there plans to add IPFS support in eas-sdk
via an external provider, or is this out of scope?
If out of scope, an example publishing to IPFS (e.g. via a local node) might be nice to ensure the data is formatted correctly and the resulting CID is as expected.
Can be tested by trying
import { OFFCHAIN_ATTESTATION_VERSION, Offchain } from "@ethereum-attestation-service/eas-sdk"
as recommended here:
https://github.com/ethereum-attestation-service/eas-sdk#verify-an-offchain-attestation
Hi guys, we want to use EAS's off-chain attestations in the upcoming EthGlobal Istanbul hackathon, but we had a few problems when pulling attestations with the api. After making the off-chain attestation, we can see the attestation thanks to the url on easscan.org, but when we try to pull it from the GraphQL Api, nothing appears on behalf of the attestation. When we manually publish to ipfs via easscan, we can then pull the attestation from GraphQL, but we need to do this programmatically. We need some help on this issue. I actually tried to reach you on twitter but I guess none of your dm boxes were open. You can find my twitter and discord handles in my github profile, it would be good if we can chat a bit about this
**The examples for creating both onchain and offchain attestations generates various errors:
onchain: return [4 /yield/, signerOrProvider.call(tx, blockTag)];
offchain: 'invalid hexlify value' NOTE: leads to further errors even if value ignored.
please advise. thx.**
I am trying to integrate eas-sdk into a Next13 repo:
I have tried both version 1.5.0, and the beta 2.0.0v yet I can't get this working.
import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk";
import { TransactionSigner } from "@ethereum-attestation-service/eas-sdk";
import { useEthersSigner } from "./userEthersSigner";
import { useEffect, useState } from "react";
// EAS Schema https://optimism.easscan.org/schema/view/0x081fc803f607b291b727b885a203d53b8cbb1488f6db1242327cca81db5f17ed
const easContractAddress = "0x4200000000000000000000000000000000000021";
const schemaUID = "0x081fc803f607b291b727b885a203d53b8cbb1488f6db1242327cca81db5f17ed";
const eas = new EAS(easContractAddress); // ERROR HERE: TypeError: (0 , ethers_1.toUtf8Bytes) is not a function
export const useEAS = () => {
const [connectedEAS, setConnectedEAS] = useState<EAS | null>(null);
const provider = useEthersSigner({ chainId: 10 });
useEffect(() => {
const connectEAS = async () => {
if (provider) {
eas.connect(provider); // TYPE ERROR HERE Argument of type is not assignable to parameter of type Transaction Signer
}
setConnectedEAS(eas);
}
connectEAS();
}, [provider])
const attest = async (message: string, context: string) => {
// Initialize SchemaEncoder with the schema string
const schemaEncoder = new SchemaEncoder("string message,string context");
const encodedData = schemaEncoder.encodeData([
{ name: "message", value: message, type: "string" },
{ name: "context", value: context, type: "string" }
]);
const tx = await eas.attest({
schema: schemaUID,
data: {
recipient: "0x0000000000000000000000000000000000000000",
expirationTime: 0 as unknown as bigint,
revocable: true, // Be aware that if your schema is not revocable, this MUST be false
data: encodedData,
},
});
const newAttestationUID = await tx.wait();
console.log("New attestation UID:", newAttestationUID);
}
return { connectedEAS, attest };
}
I haven't been able to move this forward, looked into the open/closed issues on Github.
Hi!
I'm working on a project using EAS where I can to create offchain signatures and embed as QR codes to be verified. The QR code should point to the EAS scanner so I'm trying to figure out how to generate the attestation id used in the URL.
From my research I've found that the id is a gzipped base64 encoded string (with encodeURIComponent).
I have been able to successfully decode it into a valid javascript array with the following:
const pako = require("pako")
const id = decodeURIComponent("eNqlkDuO...")
// Create buffer from decoded base64
const buffer = Buffer.from(atob(id), "binary");
// Unzip using pako
const decompressed = pako.inflate(buffer, { to: "string" });
This gives the following array:
[
"0.26",
1, // version
"0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587", // verifying contract
"0x394260c8d8f8e87bd22395badce7bfece8e9474006a3f1d3aef45298599000dd", // sig.r
"0x58a8ad8e6b8767c6401de87d701a2b65475587e1228600399091c180b660431b", // sig.s
28, // sig.v
"0x0fb166cDdF1387C5b63fFa25721299fD7b068f3f", // signer address
"0xb24f6e2fe9562195ef56eb7c766af54202d7a3255e06a1dfa29fc310b11f16c3", // uid
"0x85500e806cf1e74844d51a20a6d893fe1ed6f6b0738b50e43d774827d08eca61", // schema
"0", // ?
1680884900, // message.time
0, // ?
"0", // ?
true, // message.revocable
"0x0000000000000000000000000000000000000000000000000000000000000001", // message.data
0, // ?
null // ?
];
I should then be able to compress it into the original ID:
const compressed = pako.deflate(JSON.stringify(decompressed), { to: "string" });
encodeURIComponent(Buffer.from(compressed).toString("base64"));
I haven't been able to get the same ID as in the URL. This one starts with:
eJylkTlOA0AMRe%...t8AP0qn6m
Here's the code:
https://replit.com/@CarlBarrdahl/PakoTest#index.js
Questions:
Grateful for any help!
Hey guys!
Just thinking out loud here, but how cool would it be to have a little section in the docs about using the SDK in the frontend? ๐ค Especially after #46.
Oh, and speaking of making things easier, I made this little React package to help devs with the integration with React. Would be super cool if you could check it out and let me know what you think. ๐๐ธ
Repo: react-eas on Github
npm: react-eas on npm
BTW thanks for the amazing work you're dong at EAS! ๐ช๐ฅโญ
Uncaught (in promise) TypeError: this.contract.getAddress is not a function
so what happens is that,
as soon as the application reaches at the line
const offchain = await eas.getOffchain();
It gives the following error
Uncaught (in promise) TypeError: this.contract.getAddress is not a function
I am not using typescript, just simple javascript with react.
In our dApp https://app.fairsharing.xyz/, when we make an onchain attestaion call, metamask returned the error as below snapshot,
We use EAS + Metamask + etherjs. When we change wallet app to like OKX, it works well.
I found a relative issue ethers-io/ethers.js#3926, seems we have to wait for etherjs to fix?
Or metamask should get this fixed?
Or we have to replace etherjs?
Please help look into this issue, it is blocking many users using our dApp now.
This might just be a docs issue, however, the offchain example is failing for me because of refUID
missing in the call to signOffchainAttestation
as ethers
runs into an issue when hashing:
/eas-sdk-test/node_modules/@ethersproject/bytes/lib/index.js:9
return !!(value.toHexString);
^
TypeError: Cannot read properties of undefined (reading 'toHexString')
at isHexable (/eas-sdk-test/node_modules/@ethersproject/bytes/lib/index.js:9:21)
at arrayify (/eas-sdk-test/node_modules/@ethersproject/bytes/lib/index.js:69:9)
at _pack (/eas-sdk-test/node_modules/@ethersproject/solidity/lib/index.js:53:34)
at /eas-sdk-test/node_modules/@ethersproject/solidity/lib/index.js:83:20
at Array.forEach (<anonymous>)
at pack (/eas-sdk-test/node_modules/@ethersproject/solidity/lib/index.js:82:11)
at keccak256 (/eas-sdk-test/node_modules/@ethersproject/solidity/lib/index.js:89:39)
at getOffchainUID (/eas-sdk-test/node_modules/@ethereum-attestation-service/eas-sdk/dist/utils.js:14:94)
at Offchain.getOffchainUID (/eas-sdk-test/node_modules/@ethereum-attestation-service/eas-sdk/dist/offchain/offchain.js:59:43)
at Offchain.signOffchainAttestation (/eas-sdk-test/node_modules/@ethereum-attestation-service/eas-sdk/dist/offchain/offchain.js:40:30)
Node.js v19.8.1
Setting refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
solves this:
const newAttestationUID = await offchain.signOffchainAttestation({
recipient: '0xFD50b031E778fAb33DfD2Fc3Ca66a1EeF0652165',
// Unix timestamp of when attestation expires. (0 for no expiration)
expirationTime: 0,
// Unix timestamp of current time
revocable: 0,
time: 1671219636,
nonce: 0,
schema: "0xb16fa048b0d597f5a821747eba64efa4762ee5143e9a80600d0005386edfc995",
refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
data: encodedData,
}, signer);
Adding the revocable
param has no influence, but worth noting if this is just a doc cleanup.
i use sepolia testnet, code look like this:
import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk";
const eas = new EAS(EASContractAddress);
eas.connect(signer);
// Initialize SchemaEncoder with the schema string
const schemaEncoder = new SchemaEncoder("uint256 eventId, uint8 voteIndex");
const encodedData = schemaEncoder.encodeData([
{ name: "eventId", value: 1, type: "uint256" },
{ name: "voteIndex", value: 1, type: "uint8" },
]);
const schemaUID = "0xb16fa048b0d597f5a821747eba64efa4762ee5143e9a80600d0005386edfc995";
const tx = await eas.attest({
schema: schemaUID,
data: {
recipient: "0xFD50b031E778fAb33DfD2Fc3Ca66a1EeF0652165",
expirationTime: 0,
revocable: true,
data: encodedData,
},
});
const newAttestationUID = await tx.wait();
console.log("New attestation UID:", newAttestationUID);
error:
Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"reason":"execution reverted","code":"UNPREDICTABLE_GAS_LIMIT","method":"estimateGas","transaction":{"from":"0xE65a34b090daF08C6C1eE4fDd35FCc5Ff794239C","maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x59682f00"},"maxFeePerGas":{"type":"BigNumber","hex":"0x59682f12"},"to":"0xC2679fBD37d54388Ce493F1DB75320D236e1815e","data":"0xf17325e70000000000000000000000000000000000000000000000000000000000000020b1f077940c6b2d07d05412d11ef2c5bfd8fc9aadfc89ae87ec649640fc191e860000000000000000000000000000000000000000000000000000000000000040000000000000000000000000e65a34b090daf08c6c1ee4fdd35fcc5ff794239c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000562616a6965000000000000000000000000000000000000000000000000000000","type":2,"accessList":null}}, tx={"data":"0xf17325e70000000000000000000000000000000000000000000000000000000000000020b1f077940c6b2d07d05412d11ef2c5bfd8fc9aadfc89ae87ec649640fc191e860000000000000000000000000000000000000000000000000000000000000040000000000000000000000000e65a34b090daf08c6c1ee4fdd35fcc5ff794239c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000562616a6965000000000000000000000000000000000000000000000000000000","to":{},"from":"0xE65a34b090daF08C6C1eE4fDd35FCc5Ff794239C","type":2,"maxFeePerGas":{"type":"BigNumber","hex":"0x59682f12"},"maxPriorityFeePerGas":{"type":"BigNumber","hex":"0x59682f00"},"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.7.0)
at Logger.Object.<anonymous>.Logger.makeError (/Users/weiguangchao/binglian/eas-demo/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
at Logger.Object.<anonymous>.Logger.throwError (/Users/weiguangchao/binglian/eas-demo/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
at /Users/weiguangchao/binglian/eas-demo/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:301:31
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Promise.all (index 7)
and i also meet some error when use web app, link is https://sepolia.easscan.org/attestation/attestWithSchema/0xb1f077940c6b2d07d05412d11ef2c5bfd8fc9aadfc89ae87ec649640fc191e86
thanks.
Hi @slavik0329 , I see we only have on-chain/off-chain attestation examples.
Please add some examples about delegated on-chain attestation, as well as some delegated proxy on-chain attestation.
Thanks. โค๏ธ
Currently I am using the code from the tests. I use signDelegatedProxyAttestation
on server side, then use attestByDelegationProxy
on the client side, to achieve this feature: "you have a single entity like a KYC provider attesting to many users while wanting the users to pay for the gas" . I haven't get it work correctly.
Anyone else seeing this?
MetaMask/metamask-extension#19826
Happens for me on all chains now, either in my own frontend or using the easscan.org site when creating new attestations.
I create the scheme with the resolver contract.
But when I make the off-chain attestation, it seems that just sign the data without passing the resolver contract.
Is this reasonable? Would you consider improving it in the future?
ps: I read the docs about Resolver Contracts, which didn't indicate about off-chain.
Others give me an offchain attestation. How to verify if it is valid and not modified.
Hey @slavik0329,
Should the primary type here be "Attest" instead of "Attestation"?
eas-sdk/src/offchain/offchain.ts
Line 85 in b68b35f
I am following https://github.com/ethereum-attestation-service/eas-sdk?tab=readme-ov-file#creating-offchain-attestations to create an offchain attestation. But at this line
"const offchain = await eas.getOffchain();"
it's giving me
"this.contract.getAddress is not a function" error.
https://easscan.org/schema/view/0xf58b8b212ef75ee8cd7e8d803c37c03e0519890502d5e99ee2412aae1456cafe
This is the schema I am using to test.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.