Skip to content

Instantly share code, notes, and snippets.

@sarvagnakadiya
Last active April 1, 2024 13:34
Show Gist options
  • Save sarvagnakadiya/1aaf6a3624e128bebe026286116367dc to your computer and use it in GitHub Desktop.
Save sarvagnakadiya/1aaf6a3624e128bebe026286116367dc to your computer and use it in GitHub Desktop.
const express = require("express");
const {
SchemaEncoder,
SchemaRegistry,
createOffchainURL,
EAS,
Delegated,
ZERO_BYTES32,
NO_EXPIRATION,
} = require("@ethereum-attestation-service/eas-sdk");
const { ethers } = require("ethers");
const dotenv = require("dotenv");
const { stringToBytes, bytesToHex } = require("viem");
const bodyParser = require("body-parser");
const axios = require("axios");
const app = express();
app.use(bodyParser.json());
const port = 3003;
dotenv.config();
const url = process.env.RPC_URL;
// Set up your ethers provider and signer
const provider = new ethers.JsonRpcProvider(url, undefined, {
staticNetwork: true,
});
const privateKey = process.env.PVT_KEY;
const signer = new ethers.Wallet(privateKey, provider);
const EASContractAddress = "0x4200000000000000000000000000000000000021";
// const EASContractAddress = "0x4200000000000000000000000000000000000021";
// const eas = new EAS(EASContractAddress);
// eas.connect(signer);
BigInt.prototype.toJSON = function () {
return this.toString();
};
app.post("/attestOffchain", async (req, res) => {
const eas = new EAS(EASContractAddress);
eas.connect(signer);
const { recipient, meetingId, meetingType, startTime, endTime } = req.body;
if (typeof recipient !== "string" || typeof meetingId !== "string") {
return res
.status(400)
.json({ error: "Recipient and meetingId must be strings." });
} else if (
typeof meetingType !== "number" ||
typeof startTime !== "number" ||
typeof endTime !== "number"
) {
return res
.status(400)
.json({ error: "MeetingType, startTime, and endTime must be numbers." });
} else if (meetingType < 0 || meetingType > 5) {
return res
.status(400)
.json({ error: "MeetingType must be a number between 0 and 5." });
}
try {
const offchain = await eas.getOffchain();
const schemaEncoder = new SchemaEncoder(
"bytes16 MeetingId,uint8 MeetingType,uint32 StartTime,uint32 EndTime"
);
const encodedData = schemaEncoder.encodeData([
{
name: "MeetingId",
value: bytesToHex(stringToBytes(meetingId), { size: 16 }),
type: "bytes16",
},
{ name: "MeetingType", value: meetingType, type: "uint8" },
{ name: "StartTime", value: startTime, type: "uint32" },
{ name: "EndTime", value: endTime, type: "uint32" },
]);
// Convert BigInt values to strings
const expirationTime = BigInt(0);
const currentTime = BigInt(Math.floor(Date.now() / 1000));
console.log(typeof currentTime);
const offchainAttestation = await offchain.signOffchainAttestation(
{
// schema:
// "0xfabbfe80a9120eb3d709b8f72a6cc186ad1da170e19660c1c22f695f2f5c7eee",
schema:
"0xb8ff8ae05f706119287ed047b92de57f45f1e3520150c1af8155b26da8ff94d6",
recipient: recipient,
time: currentTime,
expirationTime: expirationTime,
revocable: false,
refUID:
"0x0000000000000000000000000000000000000000000000000000000000000000",
data: encodedData,
},
signer
);
const pkg = {
sig: offchainAttestation,
signer: await signer.getAddress(),
};
const baseUrl = "https://optimism-sepolia.easscan.org";
const url = baseUrl + createOffchainURL(pkg);
const data = {
filename: `eas.txt`,
textJson: JSON.stringify(pkg),
};
let uploadstatus;
try {
response = await axios.post(`${baseUrl}/offchain/store`, data);
if (response.data) {
uploadstatus = true;
}
console.log(response.data);
} catch (error) {
console.error("Error submitting signed attestation: ", error);
throw error;
}
res.json({ success: true, offchainAttestation, url, uploadstatus });
} catch (error) {
console.error("Error:", error);
res.status(500).json({ success: false, error: error.message });
}
});
app.post("/attestOnchain", async (req, res) => {
const eas = new EAS(EASContractAddress);
eas.connect(signer);
const { recipient, meetingId, meetingType, startTime, endTime } = req.body;
if (typeof recipient !== "string" || typeof meetingId !== "string") {
return res
.status(400)
.json({ error: "Recipient and meetingId must be strings." });
} else if (
typeof meetingType !== "number" ||
typeof startTime !== "number" ||
typeof endTime !== "number"
) {
return res
.status(400)
.json({ error: "MeetingType, startTime, and endTime must be numbers." });
} else if (meetingType < 0 || meetingType > 5) {
return res
.status(400)
.json({ error: "MeetingType must be a number between 0 and 5." });
}
try {
const schemaEncoder = new SchemaEncoder(
"bytes32 MeetingId,uint8 MeetingType,uint32 StartTime,uint32 EndTime"
);
const encodedData = schemaEncoder.encodeData([
{
name: "MeetingId",
value: bytesToHex(stringToBytes(meetingId), { size: 32 }),
type: "bytes32",
},
{ name: "MeetingType", value: meetingType, type: "uint8" },
{ name: "StartTime", value: startTime, type: "uint32" },
{ name: "EndTime", value: endTime, type: "uint32" },
]);
// console.log(encodedData);
const schemaUID =
"0xb8ff8ae05f706119287ed047b92de57f45f1e3520150c1af8155b26da8ff94d6";
// const schemaUID =
// "0xb8ff8ae05f706119287ed047b92de57f45f1e3520150c1af8155b26da8ff94d6";
const tx = await eas.attest({
schema: schemaUID,
data: {
recipient: recipient,
expirationTime: 0,
revocable: false,
data: encodedData,
},
gasLimit: 300000,
});
const newAttestationUID = await tx.wait();
console.log("New attestation UID:", newAttestationUID);
res.json({ success: true, newAttestationUID });
} catch (error) {
console.error("Error:", error);
res.status(500).json({ success: false, error: error.message });
}
});
app.post("/delegateAttestationOnchain", async (req, res) => {
const { recipient, meetingId, meetingType, startTime, endTime } = req.body;
if (typeof recipient !== "string" || typeof meetingId !== "string") {
return res
.status(400)
.json({ error: "Recipient and meetingId must be strings." });
} else if (
typeof meetingType !== "number" ||
typeof startTime !== "number" ||
typeof endTime !== "number"
) {
return res
.status(400)
.json({ error: "MeetingType, startTime, and endTime must be numbers." });
} else if (meetingType < 0 || meetingType > 5) {
return res
.status(400)
.json({ error: "MeetingType must be a number between 0 and 5." });
}
try {
const schemaEncoder = new SchemaEncoder(
"bytes32 MeetingId,uint8 MeetingType,uint32 StartTime,uint32 EndTime"
);
console.log(bytesToHex(stringToBytes(meetingId), { size: 32 }));
const encodedData = schemaEncoder.encodeData([
{
name: "MeetingId",
value: bytesToHex(stringToBytes(meetingId), { size: 32 }),
type: "bytes32",
},
{ name: "MeetingType", value: meetingType, type: "uint8" },
{ name: "StartTime", value: startTime, type: "uint32" },
{ name: "EndTime", value: endTime, type: "uint32" },
]);
const schemaUID =
"0xb8ff8ae05f706119287ed047b92de57f45f1e3520150c1af8155b26da8ff94d6";
try {
const eas = new EAS(EASContractAddress);
const signerUser = new ethers.Wallet(process.env.USER_PVT_KEY, provider);
console.log("thesigner", signerUser);
eas.connect(signer);
// const delegated = new Delegated({
// address: ,
// chainId: BigInt(11155420),
// version: "1.3.0",
// });
console.log("hi");
// const gett = eas.getEIP712Proxy();
// console.log("the proxy", gett); // it is returning undefined everytime
const delegated = await eas.getDelegated();
console.log("delegated obj", delegated);
// console.log("the nonce", await eas.getNonce(signer.address));
console.log("signing atttestation ...");
const delegatedAttestation = await delegated.signDelegatedAttestation(
{
schema: schemaUID,
recipient: recipient,
expirationTime: NO_EXPIRATION,
revocable: false,
refUID: ZERO_BYTES32,
data: encodedData,
value: BigInt(0),
deadline: BigInt(0),
nonce: await eas.getNonce(signer.address),
},
signer
);
console.log(delegatedAttestation);
// console.log(
// "delegatedAttestation: (signed obj): ",
// delegatedAttestation
// );
// console.log("verifying...");
// const verify = await delegated.verifyDelegatedAttestationSignature(
// await signer.getAddress(),
// delegatedAttestation
// );
// console.log("verify obj", verify);
console.log("wallet.address", signerUser.address);
const tx = await eas.connect(signerUser).attestByDelegationProxy({
schema: schemaUID,
data: {
recipient: recipient,
data: encodedData,
expirationTime: NO_EXPIRATION,
revocable: false,
refUID: ZERO_BYTES32,
value: BigInt(0),
},
signature: delegatedAttestation.signature,
attester: "0x8dEa0ad941d577e356745d758b30Fa11EFa28E80",
deadline: BigInt(0),
});
const newAttestationUID = await tx.wait();
console.log("New attestation UID:", newAttestationUID);
res.json({ success: true, newAttestationUID });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
} catch (error) {
console.error("Error:", error);
res.status(500).json({ success: false, error: error.message });
}
});
app.post("/registerSchema", async (req, res) => {
const eas = new EAS(EASContractAddress);
eas.connect(signer);
try {
const schemaRegistryContractAddress =
"0x4200000000000000000000000000000000000020";
const schemaRegistry = new SchemaRegistry(schemaRegistryContractAddress);
schemaRegistry.connect(signer);
const schema =
"bytes32 meetingId, uint8 meetingType, uint32 startTime, uint32 endTime";
const resolverAddress = "0x6a5978120d5E3d16bc1C608DdefE9a78404a578A";
const revocable = false;
const transaction = await schemaRegistry.register({
schema,
resolverAddress,
revocable,
});
// console.log(transaction);
// Optional: Wait for transaction to be validated
const hash = await transaction.wait();
console.log("the schema UID", hash);
res.json({ success: true, transaction, hash });
} catch (error) {
console.error("Error:", error);
res.status(500).json({ success: false, error: error.message });
}
});
// Start the server
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
@sarvagnakadiya
Copy link
Author

See this is my delegatedAttestation object:

`delegatedAttestation {
domain: {
name: 'EAS',
version: '1.0.2',
chainId: 11155420n,
verifyingContract: '0x4200000000000000000000000000000000000021'
},
primaryType: 'Attest',
message: {
schema: '0x69179097bdb0b8abaaa479db62cfee2416f14491c67da3705c4fae60019a8867',
recipient: '0x97861976283e6901b407D1e217B72c4007D9F64D',
expirationTime: 0n,
revocable: false,
refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
data: '0x7465732d747365662d676800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000065e048700000000000000000000000000000000000000000000000000000000065e0487a',
nonce: 45
},
types: {
Attest: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
]
},

signature: {
v: 27,
r: '0x3420b2e99949ad087b71d10b3cb2c0cdcf827404d02acb8f634a8c6ac0c2c68e',
s: '0x4b087817d588b6b1f991d167f4837f87ff2d8cd18ddfb90431208016fc564eac'
}
}`

@sarvagnakadiya
Copy link
Author

but this error is coming everytime

"missing revert data (action=\"estimateGas\", data=null, reason=null, transaction={ \"data\": \"0x3c042715000000000000000000000000000000000000000000000000000000000000002069179097bdb0b8abaaa479db62cfee2416f14491c67da3705c4fae60019a886700000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000001b3420b2e99949ad087b71d10b3cb2c0cdcf827404d02acb8f634a8c6ac0c2c68e4b087817d588b6b1f991d167f4837f87ff2d8cd18ddfb90431208016fc564eac0000000000000000000000008dea0ad941d577e356745d758b30fa11efa28e800000000000000000000000000000000000000000000000000000000063c58ce800000000000000000000000097861976283e6901b407d1e217b72c4007d9f64d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000807465732d747365662d676800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000065e048700000000000000000000000000000000000000000000000000000000065e0487a\", \"from\": \"0x97861976283e6901b407D1e217B72c4007D9F64D\", \"to\": \"0x4200000000000000000000000000000000000021\" }, invocation=null, revert=null, code=CALL_EXCEPTION, version=6.11.0)

@sarvagnakadiya
Copy link
Author

sarvagnakadiya commented Mar 9, 2024

log after code updated with getNonce

Server is running on http://localhost:3003
signing atttestation ...
thesigner Wallet {
provider: JsonRpcProvider {},
address: '0x97861976283e6901b407D1e217B72c4007D9F64D'
}
hi
delegated obj Delegated {
config: {
address: '0x4200000000000000000000000000000000000021',
version: '1.0.2',
chainId: 11155420n,
name: 'EAS'
},
version: 0,
attestType: {
typedSignature: 'Attest(bytes32 schema,address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes data,uint256 nonce)',
primaryType: 'Attest',
types: { Attest: [Array] }
},
revokeType: {
typedSignature: 'Revoke(bytes32 schema,bytes32 uid,uint256 nonce)',
primaryType: 'Revoke',
types: { Revoke: [Array] }
}
}
the nonce 0n
delegatedAttestation {
domain: {
name: 'EAS',
version: '1.0.2',
chainId: 11155420n,
verifyingContract: '0x4200000000000000000000000000000000000021'
},
primaryType: 'Attest',
message: {
schema: '0x0208c82b51526b639b4d7e3334fd476d7f9a21e02e8c121ef4eb681429119a1d',
recipient: '0x97861976283e6901b407D1e217B72c4007D9F64D',
expirationTime: 0n,
revocable: false,
refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
data: '0x7465732d747365662d676800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000065e048700000000000000000000000000000000000000000000000000000000065e0487a',
nonce: 0n
},
types: {
Attest: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
]
},
signature: {
v: 27,
r: '0x84d353d5b4328639eeebcff04c9f84fb263033037f8e72761b092e654e838653',
s: '0x1fb7731590278c23a388e3debdaa960966c892bdd3f039a86e0698957006b433'
}
}
verifying...
verify obj true
wallet.address 0x97861976283e6901b407D1e217B72c4007D9F64D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment