blocto / solana-go-sdk

Solana Golang SDK
https://blocto.github.io/solana-go-sdk/
MIT License
389 stars 102 forks source link

Sign transaction outside of CreateRawTransaction #14

Closed Lazar955 closed 3 years ago

Lazar955 commented 3 years ago

Hey really love the SDK, and nice job creating it.

I was wondering if there is the ability to sign a transaction outside of the types.CreateRawTransaction function, and just provide the signature of the raw tx before sending it (if I am using an external service for signing tx).

Best regards,

yihau commented 3 years ago

Hi! For now you can use the code below

package main

import (
    "context"
    "crypto/ed25519"
    "fmt"

    "github.com/portto/solana-go-sdk/client"
    "github.com/portto/solana-go-sdk/client/rpc"
    "github.com/portto/solana-go-sdk/common"
    "github.com/portto/solana-go-sdk/types"
)

func main() {
    // connection
    c := client.NewClient(rpc.DevnetRPCEndpoint)

    // fee payer
    feePayer := types.AccountFromPrivateKeyBytes([]byte{})

    // compose message
    message := types.NewMessage(
        feePayer.PublicKey,
        []types.Instruction{},
        "RECNET BLOCK HASH HERE",
    )

    // serialize message for signing
    serilizedMessage, err := message.Serialize()
    if err != nil {
        // handle error here
    }

    // create tx with signatures
    tx, err := types.CreateTransaction(
        message,
        map[common.PublicKey]types.Signature{
            feePayer.PublicKey: ed25519.Sign(feePayer.PrivateKey, serilizedMessage),
            // other pubkey: other sig
        })
    if err != nil {
        // handle error here
    }

    // serialize tx
    rawTx, err := tx.Serialize()
    if err != nil {
        // handle error here
    }

    // send it
    sig, err := c.SendRawTransaction(context.Background(), rawTx)
    if err != nil {
        // handle error here
    }
    fmt.Println(sig)
}

I will refactor for this steps. I think it is so clumsy.

Lazar955 commented 3 years ago

Thanks for the fast response, yep that's exactly what I am looking for!

yihau commented 3 years ago

I've added a new way to make the process more elegant at v1.7.0

package main

import (
    "context"
    "fmt"

    "github.com/portto/solana-go-sdk/client"
    "github.com/portto/solana-go-sdk/client/rpc"
    "github.com/portto/solana-go-sdk/common"
    "github.com/portto/solana-go-sdk/program/sysprog"
    "github.com/portto/solana-go-sdk/types"
)

var feePayer = types.AccountFromPrivateKeyBytes()

func main() {
    // connection
    c := client.NewClient(rpc.DevnetRPCEndpoint)

    a := types.NewAccount()

    message := types.NewMessage(
        feePayer.PublicKey,
        []types.Instruction{
            sysprog.CreateAccount(
                feePayer.PublicKey,
                a.PublicKey,
                common.SystemProgramID,
                1e9,
                1,
            ),
        },
        "RECENT BLOCK HASH HERE",
    )
    rawMessage, err := message.Serialize()
    if err != nil {
        // handle error
    }

    // you can pass signer here 
    tx, err := types.NewTransaction(message, []types.Account{feePayer})
    if err != nil {
        // handle error
    }

    // or add signature later!
    tx.AddSignature(a.Sign(rawMessage))

    sig, err := c.SendTransaction2(context.Background(), tx)
    if err != nil {
        // handle error
    }
    fmt.Println(sig)
}

there are two new function