Skip to content

Instantly share code, notes, and snippets.

@esomore
Created June 24, 2018 23:47
Show Gist options
  • Save esomore/e12b89086990f0ea13031caf49565a79 to your computer and use it in GitHub Desktop.
Save esomore/e12b89086990f0ea13031caf49565a79 to your computer and use it in GitHub Desktop.
bifrost stellar setup-script
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
"github.com/pkg/errors"
. "github.com/stellar/go/build"
"github.com/stellar/go/clients/horizon"
"github.com/stellar/go/keypair"
"github.com/tyler-smith/go-bip32"
)
const myToken = "TOKEN"
const newAccounts = true
func main() {
horizon.DefaultTestNetClient.HTTP = &http.Client{Timeout: 20 * time.Second}
var issuer, distributor *keypair.Full
if newAccounts {
log.Println("New test accounts")
issuer = createKeyPair()
distributor = createKeyPair()
log.Println("Fund the test accounts")
requestTestCredits(issuer.Address())
requestTestCredits(distributor.Address())
} else {
log.Println("Load the test accounts")
x := keypair.MustParse("SBRXXXXXXX")
issuer = x.(*keypair.Full)
log.Println("Issuer public key:" + issuer.Address())
y := keypair.MustParse("SADXXXXXXXXX")
distributor = y.(*keypair.Full)
log.Println("Distributor public key:" + distributor.Address())
}
log.Println("Await funding")
awaitTestBalance(issuer.Address())
awaitTestBalance(distributor.Address())
log.Println("Trust the issuing account")
autoSeq := AutoSequence{horizon.DefaultTestNetClient}
tx, err := Transaction(
SourceAccount{distributor.Address()},
autoSeq,
TestNetwork,
Trust(myToken, issuer.Address(), Limit("10")),
)
if err != nil {
log.Fatal(err)
}
err = submitTransaction(
tx,
distributor)
if err != nil {
log.Fatal(err)
}
log.Println("Create tokens")
tx, err = Transaction(
SourceAccount{issuer.Address()},
autoSeq,
TestNetwork,
Payment(
Destination{distributor.Address()},
CreditAmount{
Code: myToken,
Issuer: issuer.Address(),
Amount: "10",
},
),
)
if err != nil {
log.Fatal(err)
}
err = submitTransaction(
tx,
issuer)
if err != nil {
log.Fatal(err)
}
log.Println("Create passive offer")
tx, err = Transaction(
SourceAccount{distributor.Address()},
autoSeq,
TestNetwork,
CreatePassiveOffer(Rate{
Selling: CreditAsset(myToken, issuer.Address()),
Buying: CreditAsset("ETH", distributor.Address()),
Price: Price("1"),
}, "10"),
)
if err != nil {
log.Fatal(err)
}
err = submitTransaction(
tx, distributor)
if err != nil {
log.Fatal(err)
}
// Generate a seed to determine all keys from.
// This should be persisted, backed up, and secured
seed, err := bip32.NewSeed()
if err != nil {
log.Fatalln("Error generating seed:", err)
}
privKey, err := bip44Key(seed)
if err != nil {
log.Fatalln("Error generating keys:", err)
}
// see: online generator: https://iancoleman.io/bip39/#english
log.Println("BIP32 address for ETH/BTC:")
log.Printf("master-private-seed: %X\n", seed)
log.Printf("master-private-key: %x\n", privKey.Key)
log.Printf("master-public: %s\n", privKey.PublicKey().String())
for i := 0; i < 10; i++ {
child1, err := privKey.NewChildKey(uint32(i))
if err != nil {
panic(err)
}
log.Printf("child-private-%d: %x\n", i, child1.Key)
}
}
func bip44Key(seed []byte) (*bip32.Key, error) {
// Create master private key from seed
// for existing keys you want to use bip32.B58Deserialize(rootKey)
privKey, err := bip32.NewMasterKey(seed)
if err != nil {
return nil, err
}
privKey, err = privKey.NewChildKey(44 + bip32.FirstHardenedChild)
if err != nil {
return nil, err
}
privKey, err = privKey.NewChildKey(60 + bip32.FirstHardenedChild)
if err != nil {
return nil, err
}
privKey, err = privKey.NewChildKey(0 + bip32.FirstHardenedChild)
if err != nil {
return nil, err
}
privKey, err = privKey.NewChildKey(0)
if err != nil {
return nil, err
}
return privKey, nil
}
func submitTransaction(tx *TransactionBuilder, signer *keypair.Full) error {
signedTX, err := tx.Sign(signer.Seed())
if err != nil {
return err
}
signedTx, err := signedTX.Base64()
if err != nil {
return err
}
if _, err = horizon.DefaultTestNetClient.SubmitTransaction(signedTx); err != nil {
x, ok := err.(*horizon.Error)
if !ok {
return err
}
msg := ""
for k, v := range x.Problem.Extras {
msg += fmt.Sprintf("%s:%s", k, v)
}
return errors.New(msg)
}
return nil
}
func createKeyPair() *keypair.Full {
pair, err := keypair.Random()
if err != nil {
log.Fatal(err)
}
log.Println("private key: " + pair.Seed())
log.Println("public key: " + pair.Address())
return pair
}
func requestTestCredits(address string) {
client := http.Client{Timeout: 90 * time.Second}
resp, err := client.Get("https://horizon-testnet.stellar.org/friendbot?addr=" + address)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
_, err = ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
}
func awaitTestBalance(address string) {
var lastErr error
var errorCount int
for errorCount < 20 {
a, err := horizon.DefaultTestNetClient.LoadAccount(address)
if err != nil {
x, ok := err.(*horizon.Error)
if !ok {
log.Fatalf("failed to load account: %s", err)
}
for k, v := range x.Problem.Extras {
log.Printf("%s:%s", k, v)
}
lastErr = err
errorCount++
time.Sleep(500 * time.Millisecond)
continue
}
for _, balance := range a.Balances {
log.Printf("++checking balance: %v", balance)
if balance.Balance == "" {
continue
}
v, _ := strconv.ParseFloat(balance.Balance, 64)
if balance.Asset.Type == "native" && v > 0. {
return
}
}
time.Sleep(500 * time.Millisecond)
}
log.Fatalf("Aborting wait for test balance: %s", lastErr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment