Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could you give me some examples ? #265

Open
godlovericea opened this issue Jan 14, 2025 · 1 comment
Open

Could you give me some examples ? #265

godlovericea opened this issue Jan 14, 2025 · 1 comment

Comments

@godlovericea
Copy link

I want to make transaction from my address to another via golang program, could you give some examples about this.

@lukechampine
Copy link
Member

The easiest way is to use walletd. After setting up a wallet, you can send siacoins using the UI, or via the API using curl, or with the Go SDK.

If you want to do things manually instead of using walletd, then the first thing you'll need is a private key. If you already have a seed phrase, you can derive the private key from that; otherwise, you can generate a new key:

import (
	"go.sia.tech/core/types"
	"go.sia.tech/coreutils/chain"
	"go.sia.tech/coreutils/wallet"
)

// derive key from seed
var seed [32]byte
wallet.SeedFromPhrase(&seed, "my seed phrase")
key := wallet.KeyFromSeed(&seed, 0)

// generate a new key
key := types.GeneratePrivateKey()

You can then derive the address for this key:

addr := types.StandardUnlockHash(key.PublicKey())

Next, you need the SiacoinOutputs controlled by this address. You can get them from the SiaCentral API:

var resp struct {
	SiacoinOutputs []struct {
		ID    types.SiacoinOutputID `json:"output_id"`
		Value types.Currency        `json:"value"`
	} `json:"siacoin_outputs"`
}
r, err := http.Get(fmt.Sprintf("https://api.siacentral.com/v2/wallet/addresses/%v/utxos/siacoin", addr))
if err != nil {
	log.Fatal(err)
} else if err := json.NewDecoder(r.Body).Decode(&resp); err != nil {
	log.Fatal(err)
}

(Alternatively, you can sync the Sia blockchain locally and scan it for outputs, but this is much more involved.)

Next, construct the transaction:

var inputs []types.SiacoinInput
var inputSum types.Currency
for _, utxo := range resp.SiacoinOutputs {
	inputs = append(inputs, types.SiacoinInput{
		ParentID:         utxo.ID,
		UnlockConditions: types.StandardUnlockConditions(key.PublicKey()),
	})
	inputSum = inputSum.Add(utxo.Value)
}
recipient := types.SiacoinOutput{
	Address: <address>,
	Value: <value>,
}
change := types.SiacoinOutput{
	Address: addr,
	Value:  inputSum.Sub(recipient.Value),
}

txn := types.Transaction{
	SiacoinInputs: inputs,
	SiacoinOutputs: []types.SiacoinOutput{recipient, change}
}

Lastly, sign and broadcast the transaction. Again, we'll use an API to do this rather than a local node:

n, _ := chain.Mainnet()
cs := n.GenesisState()
cs.Index.Height = n.HardforkFoundation.Height + 1
for _, sci := range txn.SiacoinInputs {
	sig := key.SignHash(cs.WholeSigHash(txn, types.Hash256(sci.ParentID), 0, 0, nil))
	txn.Signatures = append(txn.Signatures, types.TransactionSignature{
		ParentID:       types.Hash256(sci.ParentID),
		PublicKeyIndex: 0,
		CoveredFields:  types.CoveredFields{WholeTransaction: true},
		Signature:      sig[:],
	})
}

js, _ := json.Marshal([]types.Transaction{txn})
js = []byte(strings.NewReplacer(
	`"address":`, `"unlockhash":`,
	`"signatures":`, `"transactionsignatures":`,
).Replace(string(js)))
resp, err := http.Post("https://narwal.lukechampine.com/wallet/core-example/broadcast", "application/json", bytes.NewReader(js))
if err != nil {
	log.Fatal(err)
} 

walletd handles all of this for you, so I do recommend that approach unless you have very specific needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants