Ali Naghiee
Ali Naghiee
خواندن ۴ دقیقه·۱ سال پیش

توسعه اپلیکیشن اتریوم با استفاده از Go - اکانت

فهرست


اکانت ها در اتریوم یا آدرس‌ کیف پول هستن یا آدرس قراردادهای هوشمند.
آدرس‌ها شکلی شبیه به این دارن: 0x71c7656ec7ab88b098defb751b7401b5f6d8976fو برای ارسال اتریوم به بقیه کاربران و همینطور ارجاع به یک قرارداد هوشمند روی بلاک‌چین در زمانی که نیاز به تعامل با باهاش داشته باشیم، مورد استفاده قرار می‌گیرن. آدرس‌ها منحصر به فرد هستن و از یک کلید خصوصی ایجاد می‌شن. در بخش‌های بعدی بیشتر در مورد جفت کلیدهای عمومی/خصوصی صحبت میکنیم.
برای استفاده از آدرس‌های حساب با go-ethereum، اول باید به نوع common.Address توی go-ethereum تبدیلشون کرد.

address := common.HexToAddress("0x71c7656ec7ab88b098defb751b7401b5f6d8976f") fmt.Println(address.Hex()) // 0x71C7656EC7ab88b098defB751B7401B5f6d8976F

این نوع common.Address رو هر جایی که نیاز به پاس دادن آدرس اتریوم به متد های go-ethereum هست میبینیم.


کد کامل

package main import ( "fmt" "github.com/ethereum/go-ethereum/common" ) func main() { address := common.HexToAddress("0x71c7656ec7ab88b098defb751b7401b5f6d8976f") fmt.Println(address.Hex()) // 0x71C7656EC7ab88b098defB751B7401B5f6d8976F fmt.Println(address.Hash().Hex()) // 0x00000000000000000000000071c7656ec7ab88b098defb751b7401b5f6d8976f fmt.Println(address.Bytes()) // [113 199 101 110 199 171 136 176 152 222 251 117 27 116 1 181 246 216 151 111] }

بالانس اکانت

حالا که مبانی پایه ای اکانت و آدرس‌ها رو دیدیم، توی این بخش بالانس اکانت ها رو میگیریم.

خوندن بالانس اکانت سادست و فقط لازمه متد BalanceAt کلاینتمون رو صدا بزنیم و آدرس اکانت مورد نظرمونو بهش بدیم، به صورت انتخابی هم شماره بلاک میگیره که اگه nill قرار بدیم آخرین بالانس اکانت رو برمیگردونه.

account := common.HexToAddress("0x71c7656ec7ab88b098defb751b7401b5f6d8976f") balance, err := client.BalanceAt(context.Background(), account, nil) if err != nil { log.Fatal(err) } fmt.Println(balance) // 25893180161173005034

ولی اگه شماره بلاک رو مشخص کنیم بهمون گرفتن بالانس اکانت توی زمان اون بلاک رو میده. شماره بلاک هم باید از جنس big.Int باشه.

blockNumber := big.NewInt(5532993) balance, err := client.BalanceAt(context.Background(), account, blockNumber) if err != nil { log.Fatal(err) } fmt.Println(balance) // 25729324269165216042

اعداد توی اتریوم با کوچکترین واحد ممکن محاسبه میشن و اون واحد wei هست، برای تبدیل مقداری که اینجا گرفتیم به ETH باید محاسبه wei / 10^18 رو انجام بدیم. از اونجایی که با اعداد Big سروکار داریم باید از پکیج های math و math/big استفاده کنیم. روش انجام این محاسبه به شکل زیره.

fbalance := new(big.Float) fbalance.SetString(balance.String()) ethValue := new(big.Float).Quo(fbalance, big.NewFloat(math.Pow10(18))) fmt.Println(ethValue) // 25.729324269165216041

بالانس در انتظار

بعضی اوقات میخوایم بدونیم موجودی pending اکانت چقدره، مثلا زمانی که تازه یه تراکنش ثبت کردیم یا منتظر تایید یه تراکنش به اکانتیم. برای همچین مواقعی کلاینت یه متد مشابه BalanceAt به نام PendingBalanceAt داره که آدرس اکانت رو توی ورودیش میگیره.

pendingBalance, err := client.PendingBalanceAt(context.Background(), account) fmt.Println(pendingBalance) // 25729324269165216042

کد کامل

package main import ( "context" "fmt" "log" "math" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) func main() { client, err := ethclient.Dial("https://cloudflare-eth.com") if err != nil { log.Fatal(err) } account := common.HexToAddress("0x71c7656ec7ab88b098defb751b7401b5f6d8976f") balance, err := client.BalanceAt(context.Background(), account, nil) if err != nil { log.Fatal(err) } fmt.Println(balance) // 25893180161173005034 blockNumber := big.NewInt(5532993) balanceAt, err := client.BalanceAt(context.Background(), account, blockNumber) if err != nil { log.Fatal(err) } fmt.Println(balanceAt) // 25729324269165216042 fbalance := new(big.Float) fbalance.SetString(balanceAt.String()) ethValue := new(big.Float).Quo(fbalance, big.NewFloat(math.Pow10(18))) fmt.Println(ethValue) // 25.729324269165216041 pendingBalance, err := client.PendingBalanceAt(context.Background(), account) fmt.Println(pendingBalance) // 25729324269165216042 }

چک کردن آدرس

توی این قسمت اعتبارسنجی یک آدرس رو توضیح میدیم و اینکه چطور میشه تشخیص داد آدرس متعلق به یک قرارداد هوشمند هست یا نه.

اعتبارسنجی آدرس

میتونیم از یه Regex ساده برای اعتبارسنجی آدرس‌های اتریوم استفاده کنیم.

re := regexp.MustCompile("^0x[0-9a-fA-F]{40}$") fmt.Printf("is valid: %v\n"), re.MatchString("0x323b5d4c32345ced77393b3530b1eed0f346429d")) // is valid: true fmt.Printf("is valid: %v\n", re.MatchString("0xZYXb5d4c32345ced77393b3530b1eed0f346429d")) // is valid: false

آدرس کیف پول یا قرارداد هوشمند

اگه بایت‌کدی برای آدرس ذخیره شده باشه میتونیم تشخیص بدیم که آدرس متعلق به قرارداد هوشمنده. توی قطعه کد زیر بایت‌کد قرارداد هوشمند یک توکن رو بازیابی میکنیم و طولش رو برای تایید اینکه قرارداد هوشمنده بررسی میکنیم.

// 0x Protocol Token (ZRX) smart contract address address := common.HexToAddress("0xe41d2489571d322189246dafa5ebde1f4699f498") bytecode, err := client.CodeAt(context.Background(), address, nil) // nil is latest block if err != nil { log.Fatal(err) } isContract := len(bytecode) > 0 fmt.Printf("is contract: %v\n", isContract) // is contract: true

زمانی که بایت‌کدی وجود نداره میدونیم که آدرس متعلق به قرارداد هوشمندی نیست و برای یه اکانت استاندارد اتریومه.

// a random user account address address := common.HexToAddress("0x8e215d06ea7ec1fdb4fc5fd21768f4b34ee92ef4") bytecode, err := client.CodeAt(context.Background(), address, nil) // nil is latest block if err != nil { log.Fatal(err) } isContract = len(bytecode) > 0 fmt.Printf("is contract: %v\n", isContract) // is contract: false

کد کامل

package main import ( "context" "fmt" "log" "regexp" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) func main() { re := regexp.MustCompile("^0x[0-9a-fA-F]{40}$") fmt.Printf("is valid: %v\n", re.MatchString("0x323b5d4c32345ced77393b3530b1eed0f346429d")) // is valid: true fmt.Printf("is valid: %v\n", re.MatchString("0xZYXb5d4c32345ced77393b3530b1eed0f346429d")) // is valid: false client, err := ethclient.Dial("https://cloudflare-eth.com") if err != nil { log.Fatal(err) } // 0x Protocol Token (ZRX) smart contract address address := common.HexToAddress("0xe41d2489571d322189246dafa5ebde1f4699f498") bytecode, err := client.CodeAt(context.Background(), address, nil) // nil is latest block if err != nil { log.Fatal(err) } isContract := len(bytecode) > 0 fmt.Printf("is contract: %v\n", isContract) // is contract: true // a random user account address address = common.HexToAddress("0x8e215d06ea7ec1fdb4fc5fd21768f4b34ee92ef4") bytecode, err = client.CodeAt(context.Background(), address, nil) // nil is latest block if err != nil { log.Fatal(err) } isContract = len(bytecode) > 0 fmt.Printf("is contract: %v\n", isContract) // is contract: false }

توی پست بعدی روش ساخت کیف پول جدید و ذخیره سازی امن کلید خصوصی رو بررسی میکنیم.

لینکدین من

gethethereumgolangگولنگاتریوم
شاید از این پست‌ها خوشتان بیاید