Merge pull request #66 from lbryio/claims
Add claim management for lbrycrd client
This commit is contained in:
commit
564595cfc3
7 changed files with 374 additions and 25 deletions
2
go.mod
2
go.mod
|
@ -18,7 +18,7 @@ require (
|
||||||
github.com/gorilla/websocket v1.2.0 // indirect
|
github.com/gorilla/websocket v1.2.0 // indirect
|
||||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||||
github.com/lbryio/errors.go v0.0.0-20180223142025-ad03d3cc6a5c
|
github.com/lbryio/errors.go v0.0.0-20180223142025-ad03d3cc6a5c
|
||||||
github.com/lbryio/lbryschema.go v0.0.0-20190428231007-c54836bca002
|
github.com/lbryio/lbryschema.go v0.0.0-20190602173230-6d2f69a36f46
|
||||||
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04
|
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04
|
||||||
github.com/lbryio/types v0.0.0-20190422033210-321fb2abda9c
|
github.com/lbryio/types v0.0.0-20190422033210-321fb2abda9c
|
||||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -70,6 +70,8 @@ github.com/lbryio/errors.go v0.0.0-20180223142025-ad03d3cc6a5c h1:BhdcWGsuKif/Xo
|
||||||
github.com/lbryio/errors.go v0.0.0-20180223142025-ad03d3cc6a5c/go.mod h1:muH7wpUqE8hRA3OrYYosw9+Sl681BF9cwcjzE+OCNK8=
|
github.com/lbryio/errors.go v0.0.0-20180223142025-ad03d3cc6a5c/go.mod h1:muH7wpUqE8hRA3OrYYosw9+Sl681BF9cwcjzE+OCNK8=
|
||||||
github.com/lbryio/lbryschema.go v0.0.0-20190428231007-c54836bca002 h1:urfYK5ElpUrAv90auPLldoVC60LwiGAcY0OE6HJB9KI=
|
github.com/lbryio/lbryschema.go v0.0.0-20190428231007-c54836bca002 h1:urfYK5ElpUrAv90auPLldoVC60LwiGAcY0OE6HJB9KI=
|
||||||
github.com/lbryio/lbryschema.go v0.0.0-20190428231007-c54836bca002/go.mod h1:dAzPCBj3CKKWBGYBZxK6tKBP5SCgY2tqd9SnQd/OyKo=
|
github.com/lbryio/lbryschema.go v0.0.0-20190428231007-c54836bca002/go.mod h1:dAzPCBj3CKKWBGYBZxK6tKBP5SCgY2tqd9SnQd/OyKo=
|
||||||
|
github.com/lbryio/lbryschema.go v0.0.0-20190602173230-6d2f69a36f46 h1:LemfR+rMxhf7nnOrzy2HqS7Me7SZ5gEwOcNFzKC8ySQ=
|
||||||
|
github.com/lbryio/lbryschema.go v0.0.0-20190602173230-6d2f69a36f46/go.mod h1:dAzPCBj3CKKWBGYBZxK6tKBP5SCgY2tqd9SnQd/OyKo=
|
||||||
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04 h1:Nze+C2HbeKvhjI/kVn+9Poj/UuEW5sOQxcsxqO7L3GI=
|
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04 h1:Nze+C2HbeKvhjI/kVn+9Poj/UuEW5sOQxcsxqO7L3GI=
|
||||||
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04/go.mod h1:fbG/dzobG8r95KzMwckXiLMHfFjZaBRQqC9hPs2XAQ4=
|
github.com/lbryio/ozzo-validation v0.0.0-20170323141101-d1008ad1fd04/go.mod h1:fbG/dzobG8r95KzMwckXiLMHfFjZaBRQqC9hPs2XAQ4=
|
||||||
github.com/lbryio/types v0.0.0-20190422033210-321fb2abda9c h1:m3O7561xBQ00lfUVayW4c6SnpVbUDQtPUwGcGYSUYQA=
|
github.com/lbryio/types v0.0.0-20190422033210-321fb2abda9c h1:m3O7561xBQ00lfUVayW4c6SnpVbUDQtPUwGcGYSUYQA=
|
||||||
|
|
39
lbrycrd/channel.go
Normal file
39
lbrycrd/channel.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package lbrycrd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
c "github.com/lbryio/lbryschema.go/claim"
|
||||||
|
pb "github.com/lbryio/types/v2/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewChannel() (*c.ClaimHelper, *btcec.PrivateKey, error) {
|
||||||
|
claimChannel := new(pb.Claim_Channel)
|
||||||
|
channel := new(pb.Channel)
|
||||||
|
claimChannel.Channel = channel
|
||||||
|
|
||||||
|
pbClaim := new(pb.Claim)
|
||||||
|
pbClaim.Type = claimChannel
|
||||||
|
|
||||||
|
privateKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
pubkeyBytes, err := c.PublicKeyToDER(privateKey.PubKey())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
helper := c.ClaimHelper{Claim: pbClaim}
|
||||||
|
helper.Version = c.NoSig
|
||||||
|
helper.GetChannel().PublicKey = pubkeyBytes
|
||||||
|
helper.Tags = []string{}
|
||||||
|
coverSrc := new(pb.Source)
|
||||||
|
helper.GetChannel().Cover = coverSrc
|
||||||
|
helper.Languages = []*pb.Language{}
|
||||||
|
thumbnailSrc := new(pb.Source)
|
||||||
|
helper.Thumbnail = thumbnailSrc
|
||||||
|
helper.Locations = []*pb.Location{}
|
||||||
|
|
||||||
|
return &helper, privateKey, nil
|
||||||
|
}
|
86
lbrycrd/claim.go
Normal file
86
lbrycrd/claim.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package lbrycrd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
c "github.com/lbryio/lbryschema.go/claim"
|
||||||
|
pb "github.com/lbryio/types/v2/go"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewImageStreamClaim() (*c.ClaimHelper, error) {
|
||||||
|
streamClaim := new(pb.Claim_Stream)
|
||||||
|
stream := new(pb.Stream)
|
||||||
|
image := new(pb.Stream_Image)
|
||||||
|
image.Image = new(pb.Image)
|
||||||
|
stream.Type = image
|
||||||
|
|
||||||
|
streamClaim.Stream = stream
|
||||||
|
|
||||||
|
pbClaim := new(pb.Claim)
|
||||||
|
pbClaim.Type = streamClaim
|
||||||
|
|
||||||
|
helper := c.ClaimHelper{Claim: pbClaim}
|
||||||
|
|
||||||
|
return &helper, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVideoStreamClaim() (*c.ClaimHelper, error) {
|
||||||
|
streamClaim := new(pb.Claim_Stream)
|
||||||
|
stream := new(pb.Stream)
|
||||||
|
video := new(pb.Stream_Video)
|
||||||
|
video.Video = new(pb.Video)
|
||||||
|
stream.Type = video
|
||||||
|
streamClaim.Stream = stream
|
||||||
|
|
||||||
|
pbClaim := new(pb.Claim)
|
||||||
|
pbClaim.Type = streamClaim
|
||||||
|
|
||||||
|
helper := c.ClaimHelper{Claim: pbClaim}
|
||||||
|
|
||||||
|
return &helper, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStreamClaim(title, description string) (*c.ClaimHelper, error) {
|
||||||
|
streamClaim := new(pb.Claim_Stream)
|
||||||
|
stream := new(pb.Stream)
|
||||||
|
streamClaim.Stream = stream
|
||||||
|
|
||||||
|
pbClaim := new(pb.Claim)
|
||||||
|
pbClaim.Type = streamClaim
|
||||||
|
|
||||||
|
helper := c.ClaimHelper{Claim: pbClaim}
|
||||||
|
helper.Title = title
|
||||||
|
helper.Description = description
|
||||||
|
|
||||||
|
return &helper, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignClaim(rawTx *wire.MsgTx, privKey btcec.PrivateKey, claim, channel *c.ClaimHelper, channelClaimID string) error {
|
||||||
|
claimIDHexBytes, err := hex.DecodeString(channelClaimID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
claim.Version = c.WithSig
|
||||||
|
claim.ClaimID = rev(claimIDHexBytes)
|
||||||
|
hash, err := c.GetOutpointHash(rawTx.TxIn[0].PreviousOutPoint.Hash.String(), rawTx.TxIn[0].PreviousOutPoint.Index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sig, err := c.Sign(privKey, *channel, *claim, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lbrySig, err := sig.LBRYSDKEncode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
claim.Signature = lbrySig
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
|
@ -1,15 +1,20 @@
|
||||||
package lbrycrd
|
package lbrycrd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/lbryio/lbry.go/extras/errors"
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
c "github.com/lbryio/lbryschema.go/claim"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/btcsuite/btcd/btcjson"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/go-ini/ini"
|
"github.com/go-ini/ini"
|
||||||
)
|
)
|
||||||
|
@ -115,30 +120,6 @@ func (c *Client) SimpleSend(toAddress string, amount float64) (*chainhash.Hash,
|
||||||
return hash, nil
|
return hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (c *Client) SendWithSplit(toAddress string, amount float64, numUTXOs int) (*chainhash.Hash, error) {
|
|
||||||
// decodedAddress, err := DecodeAddress(toAddress, &MainNetParams)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, errors.Wrap(err, 0)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// amountPerAddress, err := btcutil.NewAmount(amount / float64(numUTXOs))
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, errors.Wrap(err, 0)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// amounts := map[btcutil.Address]btcutil.Amount{}
|
|
||||||
// for i := 0; i < numUTXOs; i++ {
|
|
||||||
// addr := decodedAddress // to give it a new address, so
|
|
||||||
// amounts[addr] = amountPerAddress
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// hash, err := c.Client.SendManyMinConf("", amounts, 0)
|
|
||||||
// if err != nil && err.Error() == "-6: Insufficient funds" {
|
|
||||||
// err = errors.Wrap(errInsufficientFunds, 0)
|
|
||||||
// }
|
|
||||||
// return hash, errors.Wrap(err, 0)
|
|
||||||
//}
|
|
||||||
|
|
||||||
func getLbrycrdURLFromConfFile() (string, error) {
|
func getLbrycrdURLFromConfFile() (string, error) {
|
||||||
if os.Getenv("HOME") == "" {
|
if os.Getenv("HOME") == "" {
|
||||||
return "", errors.Err("no $HOME var found")
|
return "", errors.Err("no $HOME var found")
|
||||||
|
@ -180,3 +161,130 @@ func getLbrycrdURLFromConfFile() (string, error) {
|
||||||
|
|
||||||
return "rpc://" + userpass + host + ":" + port, nil
|
return "rpc://" + userpass + host + ":" + port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateBaseRawTx(inputs []btcjson.TransactionInput, change float64) (*wire.MsgTx, error) {
|
||||||
|
addresses := make(map[btcutil.Address]btcutil.Amount)
|
||||||
|
changeAddress, err := c.GetNewAddress("")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
changeAmount, err := btcutil.NewAmount(change)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
addresses[changeAddress] = changeAmount
|
||||||
|
lockTime := int64(0)
|
||||||
|
return c.CreateRawTransaction(inputs, addresses, &lockTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetEmptyTx(totalOutputSpend float64) (*wire.MsgTx, error) {
|
||||||
|
totalFees := 0.1
|
||||||
|
unspentResults, err := c.ListUnspentMin(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
finder := newOutputFinder(unspentResults)
|
||||||
|
|
||||||
|
outputs, err := finder.nextBatch(totalOutputSpend + totalFees)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(outputs) == 0 {
|
||||||
|
return nil, errors.Err("Not enough spendable outputs to create transaction")
|
||||||
|
}
|
||||||
|
inputs := make([]btcjson.TransactionInput, len(outputs))
|
||||||
|
var totalInputSpend float64
|
||||||
|
for i, output := range outputs {
|
||||||
|
inputs[i] = btcjson.TransactionInput{Txid: output.TxID, Vout: output.Vout}
|
||||||
|
totalInputSpend = totalInputSpend + output.Amount
|
||||||
|
}
|
||||||
|
|
||||||
|
change := totalInputSpend - totalOutputSpend - totalFees
|
||||||
|
return c.CreateBaseRawTx(inputs, change)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SignTxAndSend(rawTx *wire.MsgTx) (*chainhash.Hash, error) {
|
||||||
|
signedTx, allInputsSigned, err := c.SignRawTransaction(rawTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
if !allInputsSigned {
|
||||||
|
return nil, errors.Err("Not all inputs for the tx could be signed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendRawTransaction(signedTx, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScriptType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClaimName ScriptType = iota
|
||||||
|
ClaimUpdate
|
||||||
|
ClaimSupport
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) AddStakeToTx(rawTx *wire.MsgTx, claim *c.ClaimHelper, name string, claimAmount float64, scriptType ScriptType) error {
|
||||||
|
|
||||||
|
address, err := c.GetNewAddress("")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
amount, err := btcutil.NewAmount(claimAmount)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := claim.CompileValue()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
var claimID string
|
||||||
|
if len(claim.ClaimID) > 0 {
|
||||||
|
claimID = hex.EncodeToString(rev(claim.ClaimID))
|
||||||
|
}
|
||||||
|
var script []byte
|
||||||
|
switch scriptType {
|
||||||
|
case ClaimName:
|
||||||
|
script, err = getClaimNamePayoutScript(name, value, address)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
case ClaimUpdate:
|
||||||
|
script, err = getUpdateClaimPayoutScript(name, claimID, value, address)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
case ClaimSupport:
|
||||||
|
script, err = getUpdateClaimPayoutScript(name, claimID, value, address)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTx.AddTxOut(wire.NewTxOut(int64(amount), script))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateChannel(name string, amount float64) (*c.ClaimHelper, *btcec.PrivateKey, error) {
|
||||||
|
channel, key, err := NewChannel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTx, err := c.GetEmptyTx(amount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
err = c.AddStakeToTx(rawTx, channel, name, amount, ClaimName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.SignTxAndSend(rawTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel, key, nil
|
||||||
|
}
|
||||||
|
|
38
lbrycrd/finder.go
Normal file
38
lbrycrd/finder.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package lbrycrd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type outputFinder struct {
|
||||||
|
unspent []btcjson.ListUnspentResult
|
||||||
|
lastChecked int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOutputFinder(unspentResults []btcjson.ListUnspentResult) *outputFinder {
|
||||||
|
return &outputFinder{unspent: unspentResults, lastChecked: -1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *outputFinder) nextBatch(minAmount float64) ([]btcjson.ListUnspentResult, error) {
|
||||||
|
var batch []btcjson.ListUnspentResult
|
||||||
|
var lbcBatched float64
|
||||||
|
for i, unspent := range f.unspent {
|
||||||
|
if i > f.lastChecked {
|
||||||
|
if unspent.Spendable {
|
||||||
|
batch = append(batch, unspent)
|
||||||
|
lbcBatched = lbcBatched + unspent.Amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lbcBatched >= minAmount {
|
||||||
|
f.lastChecked = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if i == len(f.unspent)-1 {
|
||||||
|
return nil, errors.Err("Not enough unspent outputs to spend %d on supports.", minAmount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return batch, nil
|
||||||
|
}
|
76
lbrycrd/script.go
Normal file
76
lbrycrd/script.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package lbrycrd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/txscript"
|
||||||
|
"github.com/btcsuite/btcutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getClaimSupportPayoutScript(name, claimid string, address btcutil.Address) ([]byte, error) {
|
||||||
|
//OP_SUPPORT_CLAIM <name> <claimid> OP_2DROP OP_DROP OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
|
||||||
|
pkscript, err := txscript.PayToAddrScript(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := hex.DecodeString(claimid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txscript.NewScriptBuilder().
|
||||||
|
AddOp(txscript.OP_NOP7). //OP_SUPPORT_CLAIM
|
||||||
|
AddData([]byte(name)). //<name>
|
||||||
|
AddData(rev(bytes)). //<claimid>
|
||||||
|
AddOp(txscript.OP_2DROP). //OP_2DROP
|
||||||
|
AddOp(txscript.OP_DROP). //OP_DROP
|
||||||
|
AddOps(pkscript). //OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
Script()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClaimNamePayoutScript(name string, value []byte, address btcutil.Address) ([]byte, error) {
|
||||||
|
//OP_CLAIM_NAME <name> <value> OP_2DROP OP_DROP OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
|
||||||
|
pkscript, err := txscript.PayToAddrScript(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txscript.NewScriptBuilder().
|
||||||
|
AddOp(txscript.OP_NOP6). //OP_CLAIMNAME
|
||||||
|
AddData([]byte(name)). //<name>
|
||||||
|
AddData(value). //<value>
|
||||||
|
AddOp(txscript.OP_2DROP). //OP_2DROP
|
||||||
|
AddOp(txscript.OP_DROP). //OP_DROP
|
||||||
|
AddOps(pkscript). //OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
Script()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpdateClaimPayoutScript(name, claimid string, value []byte, address btcutil.Address) ([]byte, error) {
|
||||||
|
//OP_UPDATE_CLAIM <name> <claimid> <value> OP_2DROP OP_DROP OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
|
||||||
|
pkscript, err := txscript.PayToAddrScript(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := hex.DecodeString(claimid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txscript.NewScriptBuilder().
|
||||||
|
AddOp(txscript.OP_NOP8). //OP_UPDATE_CLAIM
|
||||||
|
AddData([]byte(name)). //<name>
|
||||||
|
AddData(rev(bytes)). //<claimid>
|
||||||
|
AddData(value). //<value>
|
||||||
|
AddOp(txscript.OP_2DROP). //OP_2DROP
|
||||||
|
AddOp(txscript.OP_DROP). //OP_DROP
|
||||||
|
AddOps(pkscript). //OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG
|
||||||
|
Script()
|
||||||
|
}
|
Loading…
Reference in a new issue