Skip to content

Commit 2fd02fa

Browse files
authored
Merge pull request #17 from icon-project/feature/make-contract-call
feat(transaction): implement contract call creation and broadcasting
2 parents 14cb2dc + cf1be72 commit 2fd02fa

14 files changed

+644
-218
lines changed

README.md

+47
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,53 @@ func main() {
6161
}
6262
```
6363

64+
### Creating and Broadcasting a Token Transfer Transaction
65+
```go
66+
import (
67+
"github.com/balancednetwork/stacks-go-sdk/stacks"
68+
"github.com/balancednetwork/stacks-go-sdk/clarity"
69+
)
70+
71+
func main() {
72+
network := stacks.NewStacksMainnet()
73+
74+
contractAddress := "SP466FNC0P7JWTNM2R9T199QRZN1MYEDTAR0KP27"
75+
contractName := "contract-name"
76+
functionName := "function-name"
77+
senderAddress := "SP1P72Z3704VMT3DMHPP2CB8TGQWGDBHD3RPR9GZS"
78+
senderKey := []byte{...} // sender's private key
79+
80+
// Prepare function arguments
81+
arg1, _ := clarity.NewInt(123)
82+
arg2 := clarity.NewStringType("example")
83+
functionArgs := []clarity.ClarityValue{arg1, arg2}
84+
85+
// Create and sign the transaction
86+
tx, err := stacks.MakeContractCall(
87+
contractAddress,
88+
contractName,
89+
functionName,
90+
functionArgs,
91+
*network,
92+
senderAddress,
93+
senderKey,
94+
nil, // Let the function estimate the fee
95+
nil, // Let the function fetch the nonce
96+
)
97+
if err != nil {
98+
// Handle error
99+
}
100+
101+
// Broadcast the transaction
102+
txID, err := stacks.BroadcastTransaction(tx, network)
103+
if err != nil {
104+
// Handle error
105+
}
106+
107+
println("Contract call transaction broadcast successfully. Transaction ID:", txID)
108+
}
109+
```
110+
64111
### Working with Clarity Values
65112
```golang
66113
import (

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.22.5
44

55
require (
66
github.com/btcsuite/btcd/btcec/v2 v2.3.4
7+
github.com/go-resty/resty/v2 v2.14.0
78
github.com/stretchr/testify v1.9.0
89
github.com/tyler-smith/go-bip32 v1.0.0
910
github.com/tyler-smith/go-bip39 v1.1.0
@@ -16,5 +17,6 @@ require (
1617
github.com/davecgh/go-spew v1.1.1 // indirect
1718
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
1819
github.com/pmezard/go-difflib v1.0.0 // indirect
20+
golang.org/x/net v0.27.0 // indirect
1921
gopkg.in/yaml.v3 v3.0.1 // indirect
2022
)

go.sum

+66
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK
1515
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
1616
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
1717
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
18+
github.com/go-resty/resty/v2 v2.14.0 h1:/rhkzsAqGQkozwfKS5aFAbb6TyKd3zyFRWcdRXLPCAU=
19+
github.com/go-resty/resty/v2 v2.14.0/go.mod h1:IW6mekUOsElt9C7oWr0XRt9BNSD6D5rr9mhk6NjmNHg=
20+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
1821
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1922
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2023
github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -24,15 +27,78 @@ github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJ
2427
github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE=
2528
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
2629
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
30+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
2731
golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
2832
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2933
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
34+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
35+
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
36+
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
37+
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
38+
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
3039
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
3140
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
41+
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
42+
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
43+
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
44+
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
45+
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
3246
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
47+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
48+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
49+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
50+
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
51+
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
52+
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
53+
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
54+
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
55+
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
56+
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
57+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
58+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
59+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
60+
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
61+
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
62+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3363
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
3464
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
65+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
66+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
67+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
68+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
69+
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
70+
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
71+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
72+
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
73+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
74+
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
75+
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
76+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
77+
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
78+
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
79+
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
80+
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
81+
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
82+
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
83+
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
3584
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
85+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
86+
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
87+
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
88+
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
89+
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
90+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
91+
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
92+
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
93+
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
94+
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
95+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
96+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
97+
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
98+
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
99+
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
100+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
101+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
36102
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
37103
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
38104
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

pkg/c32/c32.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ func SerializeAddress(address string) ([]byte, error) {
7272
var version byte
7373
switch address[0] {
7474
case 'S':
75-
version = 22 // Mainnet single-sig
75+
version = byte(stacks.AddressVersionMainnetSingleSig)
7676
case 'T':
77-
version = 26 // Testnet single-sig
77+
version = byte(stacks.AddressVersionTestnetSingleSig)
7878
default:
7979
return nil, fmt.Errorf("invalid address version: %c", address[0])
8080
}

pkg/c32/c32_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"testing"
77
)
88

9-
func TestCrockfordDecode(t *testing.T) {
9+
func TestC32Decode(t *testing.T) {
1010
tests := []struct {
1111
name string
1212
input string
@@ -37,14 +37,14 @@ func TestCrockfordDecode(t *testing.T) {
3737
t.Run(tt.name, func(t *testing.T) {
3838
decoded, err := C32Decode(tt.input)
3939
if (err != nil) != tt.wantErr {
40-
t.Errorf("CrockfordDecode() error = %v, wantErr %v", err, tt.wantErr)
40+
t.Errorf("C32Decode() error = %v, wantErr %v", err, tt.wantErr)
4141
return
4242
}
4343

4444
gotHex := hex.EncodeToString(decoded)
4545

4646
if !reflect.DeepEqual(gotHex, tt.expected) {
47-
t.Errorf("CrockfordDecode() = %v, want %v", gotHex, tt.expected)
47+
t.Errorf("C32Decode() = %v, want %v", gotHex, tt.expected)
4848
}
4949
})
5050
}

pkg/clarity/types_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,18 @@ func TestUIntBounds(t *testing.T) {
302302
assert.Error(t, err)
303303
})
304304
}
305+
306+
func TestAddressSerialization(t *testing.T) {
307+
address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.test-contract"
308+
expectedSerialized := "061a6d78de7b0625dfbfc16c3a8a5735f6dc3dc3f2ce0d746573742d636f6e7472616374"
309+
310+
addr, err := StringToPrincipal(address)
311+
assert.NoError(t, err)
312+
313+
serialized, err := addr.Serialize()
314+
assert.NoError(t, err)
315+
316+
serializedHex := hex.EncodeToString(serialized)
317+
318+
assert.Equal(t, expectedSerialized, serializedHex)
319+
}

pkg/crypto/signature.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func SignWithKey(privateKey []byte, messageHash string) (MessageSignature, error
4040
}
4141
signature := ecdsa.SignCompact(privKey, messageHashBytes, true)
4242

43-
recoveryID := signature[0] - 27 - 4
43+
recoveryID := signature[0] - 27 - 4 // Remove the base Bitcoin offset (27) and account for account for compressed key flag (4). For more information, see https://github.com/btcsuite/btcd/blob/master/btcec/ecdsa/signature.go#L233
4444
vrsSignature := fmt.Sprintf("%02x%s", recoveryID, hex.EncodeToString(signature[1:]))
4545
return CreateMessageSignature(vrsSignature)
4646
}

pkg/transaction/auth.go

+43-15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ type SpendingCondition struct {
2626
Signature [stacks.RecoverableECDSASigLengthBytes]byte
2727
}
2828

29+
func (t *TokenTransferTransaction) GetAuth() *TransactionAuth {
30+
return &t.Auth
31+
}
32+
33+
func (t *ContractCallTransaction) GetAuth() *TransactionAuth {
34+
return &t.Auth
35+
}
36+
37+
func (t *TokenTransferTransaction) Sign(privateKey []byte) error {
38+
return SignTransaction(t, privateKey)
39+
}
40+
41+
func (t *TokenTransferTransaction) Verify(publicKey []byte) (bool, error) {
42+
return VerifyTransaction(t, publicKey)
43+
}
44+
45+
func (t *ContractCallTransaction) Sign(privateKey []byte) error {
46+
return SignTransaction(t, privateKey)
47+
}
48+
49+
func (t *ContractCallTransaction) Verify(publicKey []byte) (bool, error) {
50+
return VerifyTransaction(t, publicKey)
51+
}
52+
2953
func (auth *TransactionAuth) Serialize() ([]byte, error) {
3054
buf := make([]byte, 0, 256)
3155

@@ -127,14 +151,15 @@ func (sc *SpendingCondition) Deserialize(data []byte) (int, error) {
127151
return 103, nil
128152
}
129153

130-
func SignTransaction(tx *TokenTransferTransaction, privateKey []byte) error {
131-
// 1. Set the fee and nonce to 0, and set the signature bytes to 0
132-
txCopy := *tx
154+
func SignTransaction(tx StacksTransaction, privateKey []byte) error {
155+
txCopy := tx.Clone()
133156

134-
txCopy.Auth.OriginAuth.Signature = [65]byte{}
157+
// 1. Set the fee and nonce to 0, and set the signature bytes to 0
158+
authCopy := txCopy.GetAuth()
135159

136-
txCopy.Auth.OriginAuth.Nonce = 0
137-
txCopy.Auth.OriginAuth.Fee = 0
160+
authCopy.OriginAuth.Signature = [65]byte{}
161+
authCopy.OriginAuth.Nonce = 0
162+
authCopy.OriginAuth.Fee = 0
138163

139164
// 2. Serialize the transaction
140165
serializedTx, err := txCopy.Serialize()
@@ -146,7 +171,8 @@ func SignTransaction(tx *TokenTransferTransaction, privateKey []byte) error {
146171
sighash := crypto.CalculateSighash(serializedTx)
147172

148173
// 4. Calculate the presign-sighash
149-
presignSighash := crypto.CalculatePresignSighash(sighash, tx.Auth.AuthType, tx.Auth.OriginAuth.Fee, tx.Auth.OriginAuth.Nonce)
174+
originalAuth := tx.GetAuth()
175+
presignSighash := crypto.CalculatePresignSighash(sighash, originalAuth.AuthType, originalAuth.OriginAuth.Fee, originalAuth.OriginAuth.Nonce)
150176

151177
// 5. Sign the presign-sighash
152178
signature, err := crypto.SignWithKey(privateKey, hex.EncodeToString(presignSighash))
@@ -156,21 +182,22 @@ func SignTransaction(tx *TokenTransferTransaction, privateKey []byte) error {
156182

157183
// 6. Set the signature in the spending condition
158184
signatureBytes, _ := hex.DecodeString(signature.Data)
159-
copy(tx.Auth.OriginAuth.Signature[:], signatureBytes)
185+
copy(originalAuth.OriginAuth.Signature[:], signatureBytes)
160186

161187
return nil
162188
}
163189

164-
func VerifyTransaction(tx *TokenTransferTransaction, publicKey []byte) (bool, error) {
165-
txCopy := *tx
190+
func VerifyTransaction(tx StacksTransaction, publicKey []byte) (bool, error) {
191+
txCopy := tx.Clone()
166192

167193
// 1. Extract the signature
168-
signature := txCopy.Auth.OriginAuth.Signature
194+
authCopy := txCopy.GetAuth()
195+
signature := authCopy.OriginAuth.Signature
169196

170197
// 2. Clear the signature in the spending condition
171-
txCopy.Auth.OriginAuth.Signature = [stacks.RecoverableECDSASigLengthBytes]byte{}
172-
txCopy.Auth.OriginAuth.Nonce = 0
173-
txCopy.Auth.OriginAuth.Fee = 0
198+
authCopy.OriginAuth.Signature = [stacks.RecoverableECDSASigLengthBytes]byte{}
199+
authCopy.OriginAuth.Nonce = 0
200+
authCopy.OriginAuth.Fee = 0
174201

175202
// 3. Serialize the transaction
176203
serializedTx, err := txCopy.Serialize()
@@ -182,7 +209,8 @@ func VerifyTransaction(tx *TokenTransferTransaction, publicKey []byte) (bool, er
182209
sighash := crypto.CalculateSighash(serializedTx)
183210

184211
// 5. Calculate the presign-sighash
185-
presignSighash := crypto.CalculatePresignSighash(sighash, tx.Auth.AuthType, tx.Auth.OriginAuth.Fee, tx.Auth.OriginAuth.Nonce)
212+
originalAuth := tx.GetAuth()
213+
presignSighash := crypto.CalculatePresignSighash(sighash, originalAuth.AuthType, originalAuth.OriginAuth.Fee, originalAuth.OriginAuth.Nonce)
186214

187215
// 6. Verify the signature
188216
messageSignature := crypto.MessageSignature{

0 commit comments

Comments
 (0)