توسعه اپلیکیشن اتریوم با استفاده از 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 }توی پست بعدی روش ساخت کیف پول جدید و ذخیره سازی امن کلید خصوصی رو بررسی میکنیم.لینکدین من