walkthrough คลิป Gasless MetaTransactions with OpenZeppelin Defender (Part 1)

Nattawat Songsom
4 min readJul 24, 2022

--

no gas no cry

Pain point

user onboarding ของ web3 มีหลายขั้นตอนมากๆ ตามรูป

user จะต้องสมัคร wallet และสมัคร exchange แล้วไปซื้อเหรียญ native coin ใน exchange เพื่อนำมาใช้เป็นค่าแก๊สของ web3

โดย meta-transaction จะเข้ามาแก้ปัญหานั้น

Meta-transaction คืออะไร ?

คือการทำให้ user ไม่ต้องจ่ายค่า gas เอง

คร่าวๆคือ relayer จะทำการนำ request ของ user มาทำการยิง tx ให้ recipient ที่ฝั่ง blockchain ตามรูป

โดยทาง relayer จะเช็คด้วยว่า request มีการ sign มา เพื่อกันการปลอมเป็น user

ข้อดีของ meta-transaction

user สามารถ onboard ได้ง่าย โดยไม่ต้องไปสมัคร exchange เพื่อซื้อค่าแก๊ส

user ไม่ต้องเสียเวลาโอนค่าแก๊สไป sidechain (ถ้าต้องการใช้ sidechain)

สามารถทำให้ครบวงจรได้ โดยการ generate wallet ให้ user ด้วย … user ก็จะไม่ต้องสมัครทั้ง wallet และ exchange

โอเค ดู component ต่างๆกัน

Stack ที่จะใช้

ในการ sign message เราจะใช้ EIP712

relayer เราจะใช้ service Autotasks webhooks relayer ของ OpenZeppelin Defender

recipient เราจะใช้ contract MinimalForwarder EIP2771 Recipient

sign message

เราจะใช้ field ดังนี้

recipient คือ contract ปลายทางที่เราจะ interact

data คือ คำสั่งที่เราจะ execute (function และ parameter)

nonce เอาไว้กัน replay attack

domain_sep เอาไว้กัน replay attack cross-forwarders

Relayer

เราจะใช้ Openzeppelin defender กัน ซึ่งจริงๆแล้วเราจะใช้ 2 service คือ Autotask และ Relayer

Autotask จะเป็น webhook (รันแบบ schedule ก็ได้) โดยจะทำหน้าที่รับ request , verify , กำหนดคนจ่าย (relayer) แล้วส่ง tx ไปยัง relayer

Relayer จะทำการ sign transaction แล้วส่ง transaction นั้นไปยัง contract

เอ จริงๆไม่ได้ซับซ้อนเลยนะ น่าจะเขียนเองได้ แล้วเราใช้ service ทำไม

จริงๆเค้าก็ให้เหตุผลมา มาดูแต่ละข้อกัน

1 เก็บ private key อย่างปลอดภัย — อันนี้ถ้าเราไม่ต้องมา setup vps เอง ก็ประหยัดเวลาอยู่ละนะ

2 manage ค่า nonce — การยิง tx ทีละมากๆ จะมีปัญหาค่า nonce ซ้ำ ได้ เค้าเลยคิดค่า nonce ให้เราเลย

3 หาค่า gas ที่ดีที่สุด — อันนี้เหมือนเค้าบอกว่า เรายังต้อง set เองอยู่ เดี๋ยวไปดูกัน

4 Automatically resubmit txs — ถ้า tx fail เค้าจะยิงใหม่ให้อัติโนมัติ

5 High availablity through multiple provider-ถ้า provider ล่ม จะเปลี่ยน provider ใหม่ เพื่อยิง tx ต่อไปได้

Recipient

เราจะใช้ contract MinimalForwarder เพื่อ

verifySignature ว่ามาจาก relayer จริงๆ

เพิ่มค่า nonce

เพิ่ม field signer โดยจะเป็น user ที่เราจ่ายค่า gas ให้

ยิง tx ไปยัง contract ปลายทาง

จากนั้น contract ปลายทางจะทำการรับ signer มา แล้วกำหนด msgSender() เพื่อไว้ดึง user ที่เราตั้งใจจะให้เรียก contract โดยเราจะใช้ msgSender() แทน msg.sender ตามมาตรฐาน EIP2771

โอเค มาดู code กัน

Demo

โดยเราจะเปลี่ยน contract name registry ให้รองรับ meta tx

contract name registry เดิมแล้วมีการทำงานดังรูป

แต่เมื่อเรา convert contract มาให้รองรับ meta tx แล้วจะมี code ดังนี้

โดยตรง constructor จะกำหนด relayer ที่เรา trust

และ msg.sender จะเปลี่ยนเป็นใช้ _msgSender() แทน

โอเค มาลองเขียน test กัน

โดยเราสามารถเรียก register แบบธรรมดาได้

หรือจะเรียกแบบ meta tx ก็ได้

จะสังเกตุเห็นว่า signed msg จะถูกส่งให้ forwarder เพื่อ concat ตัว signer และจ่ายค่า gas ให้ (forwarder ตัว relayer จะเป็นคนเรียกใช้ ดังนั้น relayer จ่ายค่าเแก๊สให้)

โอเคการ test ก็เป็นประมาณนี้

มาดูการสร้าง relayer กัน

กำหนดชื่อ และ network

โดยเมื่อสร้างเสร็จ ตัว relayer จะทำการสร้าง wallet รวมทั้ง api key ให้ ตอนนี้เราก็สามารถใช้ relayer ในการจ่ายค่า gas แทนเราได้แล้ว

ตอนเพิ่งสร้าง relayer จะไม่มีค่า gas เลย อันนี้ให้เราโอนไปเติมใน wallet ของ relayer ก่อน

โอเค พอ relayer พร้อมใช้งานแล้ว เราก็แค่ป้อน request ที่ต้องการให้กับ relayer ตาม code ดังนี้

โดยเราจะเขียน server เอง

โดยมี api ที่รับ request และ signature ที่ user sign ไว้แล้ว มาเป็น input

จากนั้นเราจะทำการ initial ตัว relayer โดยใช้ api key ที่ได้มาตอนสร้าง relayer

และทำการ connect กับตัว forward contract (อันนี้เหมือนจะยังไม่เห็น code แหะ น่าจะใช้ตัว Minimal Forwarder ตรงเลยมั้ง ตาม link นี้)

สุดท้ายทำการ custom เช็คก่อนส่งไป relayer มาดู code การ custom check กัน

อันนี้เขียนเองได้เลย แต่ใน demo ทำการเช็คว่า

ตัว contract ปลายทาง ตรงกับที่กำหนดรึเปล่า

signature ตรงกับ request รึเปล่า

กำหนดค่า gas ให้กับ tx

ให้ relayer ทำการเรียก forwarder contract เพื่อส่ง meta tx

มาดูผลลัพธ์กัน

ตัว wallet relayer จะทำการเรียก tx

โดยใน tx นั้นจะยิงจาก wallet relayer ไปยัง forwarder contract

โดยใน internal tx ประกอบด้วย 2 step คือ

wallet relayer เรียก forwarder contract

และ forwarder เรียก contract ปลายทาง

ซึ่งจริงๆก็จบละ ทำ meta tx ได้แล้ว user ที่ sign ไม่ต้องเสีย gas

แต่ส่วนเขียน api เนี่ย เราใช้ service Autotask ของ OpenZeppelin ได้ ไม่ต้องมา host เอง แต่เอาไว้ต่อ part 2 แล้วกัน

ref

https://www.youtube.com/watch?v=mhAUmULLV44&t=2225s

--

--

No responses yet