Panduan Penting untuk Abstraksi Akun di IoTeX: Panduan Praktis untuk Tanda Tangan p256
Dengan suara komunitas kami sepenuhnya mendukung Proposal Peningkatan IoTeX 14, Abstraksi Akun akhirnya muncul di Mainnet dan Testnet IoTeX, dan fitur-fiturnya kini tersedia untuk semua pengembang ekosistem. Jadi, apa itu AA, bagaimana cara kerjanya, dan bagaimana Anda dapat menggunakannya di aplikasi Anda selanjutnya?
Pengantar Singkat
Abstraksi Akun (AA) yang didefinisikan oleh ERC-4337, "memungkinkan pengguna untuk menggunakan dompet kontrak pintar yang berisi logika verifikasi sewenang-wenang alih-alih EOAs sebagai akun utama mereka." ERC-4337 memperkenalkan banyak keuntungan bagi pengalaman pengguna, terutama memungkinkan orang untuk menggunakan Kontrak Pintar sebagai akun utama mereka.
ERC-4337 berjalan di atas blockchain dan tidak memerlukan perubahan apa pun pada blockchain itu sendiri. Saat ini, kode Abstraksi Akun IoTeX didasarkan pada versi rilis ERC-4337 0.6.0.
Komponen Infrastruktur AA
Komponen infrastruktur AA adalah:
- Layanan Bundler: satu titik akhir untuk Mainnet (https://bundler.w3bstream.com) dan satu untuk Testnet (https://bundler.testnet.w3bstream.com). Sebuah bundler adalah node offchain yang mengumpulkan beberapa operasi pengguna yang terabstraksi menjadi satu transaksi yang dapat diproses oleh blockchain yang mendasarinya. Transaksi ini dikirim ke komponen tetap lainnya, yang disebut Kontrak
EntryPoint. - Kontrak
EntryPoint: Ada dua kontrakEntryPointyang dikerahkan di IoTeX, satu untuk Mainnet (0xc3527348De07d591c9d567ce1998eFA2031B8675) dan satu untuk Testnet (0xc3527348De07d591c9d567ce1998eFA2031B8675). KontrakEntryPointbertanggung jawab untuk membuat/mendeploy kontrak khusus tertentu, yang disebut kontrakAccountFactory, yang pada gilirannya bertanggung jawab untuk membuat akun tertentu (kontrak dompet) yang dapat digunakan untuk tujuan khusus.
Untuk menggunakan abstraksi akun untuk membuat akun khusus baru, ada beberapa komponen yang harus dibuat oleh pengembang dApp berdasarkan kebutuhan aplikasi mereka:
- kontrak
Account, yang menerapkan logika validasi dalam metodevalidateUserOp, dan logika eksekusi apa pun yang mungkin dibutuhkan oleh operasi pengguna. - kontrak
AccountFactory, yang bertanggung jawab, seperti yang disebutkan di atas, untuk membuat/mendeploy kontrak akun khusus baru. - Beberapa kode klien yang membangun operasi pengguna yang kompatibel dengan aturan verifikasi yang diterapkan di
AccountFactory. - Sebuah paymaster adalah bagian opsional dari arsitektur AA. IoTeX menyediakan layanan paymaster hanya untuk Testnet di https://paymaster.testnet.w3bstream.com. Peran paymaster adalah untuk mensponsori gas yang diperlukan untuk mengeksekusi operasi pengguna, baik dengan mensponsori mereka sepenuhnya atau membiarkan pengguna membayar untuknya dalam berbagai token.
Contoh: P256AccountFactory
Sebagai contoh pertama, kami telah menyediakan kontrak resmi P256AccountFactory (Mainnet 0xD98d2B6cBca981c777037c5784721d8179D7030b dan Testnet 0x508Db1A73FcBA98594679aD4f5d8D0B880BbdaFB) yang memungkinkan pengembang untuk membuat kontrak akun yang dapat memverifikasi operasi pengguna yang ditandatangani dengan kriptografi "p256", bukan dengan kurva elips "secp256k1" asli Ethereum dan IoTeX. Hal ini sangat berguna, karena memberdayakan pengembang untuk membuat aplikasi di mana pengguna dapat, misalnya, menandatangani transaksi dengan biometrik mereka, atau berpindah dari frasa benih, atau bahkan memiliki keamanan yang lebih baik ketika perangkat mereka mendukung chip keamanan khusus (misalnya Secure Element Android dan Secure Enclave Apple, dll.). Kode sumber dari P256AccountFactorycan dapat ditemukan di https://github.com/iotexproject/account-abstraction-contracts/blob/main/contracts/accounts/secp256r1/P256AccountFactory.sol sementara kontrak Abstraksi Akun sumber terbuka bergantung pada implementasi oleh penulis asli EIP-4337 untuk Ethereum di sini https://github.com/iotexproject/account-abstraction-contracts/tree/main.
Kontrak P256AccountFactory juga mendukung pengelolaan layanan paymaster, yang terdiri dari dua komponen, sebuah kontrak VerifyingPaymaster (https://github.com/iotexproject/account-abstraction-contracts/blob/main/contracts/paymaster/VerifyingPaymaster.sol) dan sebuah titik akhir layanan off-chain untuk menghasilkan bukti pembayaran untuk kontrak paymaster (https://paymaster.testnet.w3bstream.com, hanya untuk Testnet).
Kode di bawah menunjukkan kepada Anda bagaimana berinteraksi dengan implementasi akun p256 dari klien javascript untuk membuat akun:
async function main() {
// memuat kontrak yang diterapkan
const factory = (await ethers.getContract("P256AccountFactory")) as P256AccountFactory
const entryPoint = (await ethers.getContract("EntryPoint")) as EntryPoint
// sebuah akun EOA untuk mengirim UserOperations
const bundler = new ethers.Wallet(process.env.BUNDLER!, ethers.provider)
// memuat pasangan kunci secp256r1
const keyContent = fs.readFileSync(path.join(__dirname, "key.pem"))
const keyPair = ecPem.loadPrivateKey(keyContent)
const publicKey = "0x" + keyPair.getPublicKey("hex").substring(2)
const index = 0
const account = await factory.getAddress(publicKey, index)
// membuat create account UserOperation
const initCode = hexConcat([ factory.address, factory.interface.encodeFunctionData("createAccount", [publicKey, index]),
])
const createOp = {
sender: account,
initCode: initCode,
}
const fullCreateOp = await fillUserOp(createOp, entryPoint)
// stake IOTX untuk gas
const stake = await entryPoint.balanceOf(account)
if (stake.isZero()) {
console.log(`deposit gas untuk akun ${account}`)
const tx = await entryPoint
.connect(bundler)
.depositTo(account, { value: ethers.utils.parseEther("10") })
await tx.wait()
}
// tanda tangan UserOperation menggunakan kurva secp256r1
const chainId = (await ethers.provider.getNetwork()).chainId
const signedOp = await signOp(
fullCreateOp,
entryPoint.address,
chainId,
new P2565Signer(keyPair)
)
// simulasi UserOperation
const err = await entryPoint.callStatic.simulateValidation(signedOp).catch((e) => e)
if (err.errorName === "FailedOp") {
console.error(`simulasi operasi error ${err.errorArgs.at(-1)}`)
return
} else if (err.errorName !== "ValidationResult") {
console.error(`error tidak dikenal ${err}`)
return
}
console.log(`simulasi operasi berhasil`)
// kirim UserOperation ke EntryPoint
const tx = await entryPoint.connect(bundler).handleOps([signedOp], bundler.address)
console.log(`transaksi pembuatan akun: ${tx.hash}, akun: ${account}`)
}
Sementara kode berikut akan menunjukkan kepada Anda bagaimana mentransfer IOTX menggunakan layanan bundler dan paymaster:
async function main() {
const factory = (await ethers.getContract("P256AccountFactory")) as P256AccountFactory
const accountTpl = await ethers.getContractFactory("P256Account")
const entryPoint = (await ethers.getContract("EntryPoint")) as EntryPoint
const paymaster = await ethers.getContract("VerifyingPaymaster")
const bundler = new JsonRpcProvider("http://localhost:4337")
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!)
const keyContent = fs.readFileSync(path.join(__dirname, "key.pem"))
const keyPair = ecPem.loadPrivateKey(keyContent)
const publicKey = "0x" + keyPair.getPublicKey("hex").substring(2)
const index = 0
const account = await factory.getAddress(publicKey, index)
const callData = accountTpl.interface.encodeFunctionData("execute", [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
ethers.utils.parseEther("0.1"),
"0x",
])
const transferOp = {
sender: account,
callData,
preVerificationGas: 50000,
}
const fullCreateOp = await fillUserOp(transferOp, entryPoint)
fullCreateOp.paymasterAndData = hexConcat([
paymaster.address,
defaultAbiCoder.encode(["uint48", "uint48"], [0, 0]),
"0x" + "00".repeat(65),
])
const validAfter = Math.floor(new Date().getTime() / 1000)
const validUntil = validAfter + 86400 // satu hari
const pendingOpHash = await paymaster.getHash(fullCreateOp, validUntil, validAfter)
const paymasterSignature = await signer.signMessage(arrayify(pendingOpHash))
fullCreateOp.paymasterAndData = hexConcat([
paymaster.address,
defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, validAfter]),
paymasterSignature,
])
const chainId = (await ethers.provider.getNetwork()).chainId
const signedOp = await signOp(
fullCreateOp,
entryPoint.address,
chainId,
new P2565Signer(keyPair)
)
const err = await entryPoint.callStatic.simulateValidation(signedOp).catch((e) => e)
if (err.errorName === "FailedOp") {
console.error(`simulasi operasi error ${err.errorArgs.at(-1)}`)
return
} else if (err.errorName !== "ValidationResult") {
console.error(`error tidak dikenal ${err}`)
return
}
console.log(`simulasi operasi berhasil`)
const hexifiedUserOp = deepHexlify(await resolveProperties(signedOp))
const result = await bundler.send("eth_sendUserOperation", [hexifiedUserOp, entryPoint.address])
console.log(`transfer menggunakan bundler berhasil opHash: ${result}`)
}
Sisa contoh tentang bagaimana berinteraksi dengan implementasi akun p256 dari klien javascript dapat ditemukan di https://github.com/iotexproject/account-abstraction-contracts/tree/main/scripts/secp256r1