github.com/algorand/go-algorand-sdk@v1.24.0/transaction/transaction_test.go (about)

     1  package transaction
     2  
     3  import (
     4  	"encoding/base64"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/algorand/go-algorand-sdk/crypto"
    10  	"github.com/algorand/go-algorand-sdk/encoding/msgpack"
    11  	"github.com/algorand/go-algorand-sdk/mnemonic"
    12  	"github.com/algorand/go-algorand-sdk/types"
    13  )
    14  
    15  func byteFromBase64(s string) []byte {
    16  	b, _ := base64.StdEncoding.DecodeString(s)
    17  	return b
    18  }
    19  
    20  func byte32ArrayFromBase64(s string) (out [32]byte) {
    21  	slice := byteFromBase64(s)
    22  	if len(slice) != 32 {
    23  		panic("wrong length: input slice not 32 bytes")
    24  	}
    25  	copy(out[:], slice)
    26  	return
    27  }
    28  
    29  func TestMakePaymentTxn(t *testing.T) {
    30  	const fromAddress = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU"
    31  	const toAddress = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI"
    32  	const referenceTxID = "5FJDJD5LMZC3EHUYYJNH5I23U4X6H2KXABNDGPIL557ZMJ33GZHQ"
    33  	const mn = "advice pudding treat near rule blouse same whisper inner electric quit surface sunny dismiss leader blood seat clown cost exist hospital century reform able sponsor"
    34  	const golden = "gqNzaWfEQPhUAZ3xkDDcc8FvOVo6UinzmKBCqs0woYSfodlmBMfQvGbeUx3Srxy3dyJDzv7rLm26BRv9FnL2/AuT7NYfiAWjdHhui6NhbXTNA+ilY2xvc2XEIEDpNJKIJWTLzpxZpptnVCaJ6aHDoqnqW2Wm6KRCH/xXo2ZlZc0EmKJmds0wsqNnZW6sZGV2bmV0LXYzMy4womdoxCAmCyAJoJOohot5WHIvpeVG7eftF+TYXEx4r7BFJpDt0qJsds00mqRub3RlxAjqABVHQ2y/lqNyY3bEIHts4k/rW6zAsWTinCIsV/X2PcOH1DkEglhBHF/hD3wCo3NuZMQg5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGkdHlwZaNwYXk="
    35  	gh := byteFromBase64("JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=")
    36  
    37  	txn, err := MakePaymentTxn(fromAddress, toAddress, 4, 1000, 12466, 13466, byteFromBase64("6gAVR0Nsv5Y="), "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA", "devnet-v33.0", gh)
    38  	require.NoError(t, err)
    39  
    40  	key, err := mnemonic.ToPrivateKey(mn)
    41  	require.NoError(t, err)
    42  
    43  	id, bytes, err := crypto.SignTransaction(key, txn)
    44  
    45  	stxBytes := byteFromBase64(golden)
    46  	require.Equal(t, stxBytes, bytes)
    47  
    48  	require.Equal(t, referenceTxID, id)
    49  }
    50  
    51  // should fail on a lack of GenesisHash
    52  func TestMakePaymentTxn2(t *testing.T) {
    53  	const fromAddress = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU"
    54  	const toAddress = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI"
    55  
    56  	_, err := MakePaymentTxn(fromAddress, toAddress, 4, 1000, 12466, 13466, byteFromBase64("6gAVR0Nsv5Y="), "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA", "devnet-v33.0", []byte{})
    57  	require.Error(t, err)
    58  
    59  }
    60  
    61  func TestMakePaymentTxnWithLease(t *testing.T) {
    62  	const fromAddress = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU"
    63  	const toAddress = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI"
    64  	const referenceTxID = "7BG6COBZKF6I6W5XY72ZE4HXV6LLZ6ENSR6DASEGSTXYXR4XJOOQ"
    65  	const mn = "advice pudding treat near rule blouse same whisper inner electric quit surface sunny dismiss leader blood seat clown cost exist hospital century reform able sponsor"
    66  	const golden = "gqNzaWfEQOMmFSIKsZvpW0txwzhmbgQjxv6IyN7BbV5sZ2aNgFbVcrWUnqPpQQxfPhV/wdu9jzEPUU1jAujYtcNCxJ7ONgejdHhujKNhbXTNA+ilY2xvc2XEIEDpNJKIJWTLzpxZpptnVCaJ6aHDoqnqW2Wm6KRCH/xXo2ZlZc0FLKJmds0wsqNnZW6sZGV2bmV0LXYzMy4womdoxCAmCyAJoJOohot5WHIvpeVG7eftF+TYXEx4r7BFJpDt0qJsds00mqJseMQgAQIDBAECAwQBAgMEAQIDBAECAwQBAgMEAQIDBAECAwSkbm90ZcQI6gAVR0Nsv5ajcmN2xCB7bOJP61uswLFk4pwiLFf19j3Dh9Q5BIJYQRxf4Q98AqNzbmTEIOfw+E0GgR358xyNh4sRVfRnHVGhhcIAkIZn9ElYcGihpHR5cGWjcGF5"
    67  	gh := byteFromBase64("JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=")
    68  
    69  	lease := [32]byte{1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}
    70  	txn, err := MakePaymentTxn(fromAddress, toAddress, 4, 1000, 12466, 13466, byteFromBase64("6gAVR0Nsv5Y="), "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA", "devnet-v33.0", gh)
    71  	require.NoError(t, err)
    72  	txn.AddLease(lease, 4)
    73  	require.NoError(t, err)
    74  
    75  	key, err := mnemonic.ToPrivateKey(mn)
    76  	require.NoError(t, err)
    77  
    78  	id, stxBytes, err := crypto.SignTransaction(key, txn)
    79  
    80  	goldenBytes := byteFromBase64(golden)
    81  	require.Equal(t, goldenBytes, stxBytes)
    82  	require.Equal(t, referenceTxID, id)
    83  }
    84  
    85  func TestKeyRegTxn(t *testing.T) {
    86  	// preKeyRegTxn is an unsigned signed keyreg txn with zero Sender
    87  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
    88  	a, err := types.DecodeAddress(addr)
    89  	require.NoError(t, err)
    90  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
    91  	expKeyRegTxn := types.Transaction{
    92  		Type: types.KeyRegistrationTx,
    93  		Header: types.Header{
    94  			Sender:      a,
    95  			Fee:         1000,
    96  			FirstValid:  322575,
    97  			LastValid:   323575,
    98  			GenesisHash: byte32ArrayFromBase64("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="),
    99  			GenesisID:   "",
   100  		},
   101  		KeyregTxnFields: types.KeyregTxnFields{
   102  			VotePK:          byte32ArrayFromBase64("Kv7QI7chi1y6axoy+t7wzAVpePqRq/rkjzWh/RMYyLo="),
   103  			SelectionPK:     byte32ArrayFromBase64("bPgrv4YogPcdaUAxrt1QysYZTVyRAuUMD4zQmCu9llc="),
   104  			VoteFirst:       10000,
   105  			VoteLast:        10111,
   106  			VoteKeyDilution: 11,
   107  		},
   108  	}
   109  	const signedGolden = "gqNzaWfEQEA8ANbrvTRxU9c8v6WERcEPw7D/HacRgg4vICa61vEof60Wwtx6KJKDyvBuvViFeacLlngPY6vYCVP0DktTwQ2jdHhui6NmZWXNA+iiZnbOAATsD6JnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAATv96ZzZWxrZXnEIGz4K7+GKID3HWlAMa7dUMrGGU1ckQLlDA+M0JgrvZZXo3NuZMQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2kdHlwZaZrZXlyZWendm90ZWZzdM0nEKZ2b3Rla2QLp3ZvdGVrZXnEICr+0CO3IYtcumsaMvre8MwFaXj6kav65I81of0TGMi6p3ZvdGVsc3TNJ38="
   110  	// now, sign
   111  	private, err := mnemonic.ToPrivateKey(addrSK)
   112  	require.NoError(t, err)
   113  	txid, newStxBytes, err := crypto.SignTransaction(private, expKeyRegTxn)
   114  	require.NoError(t, err)
   115  	require.Equal(t, "MDRIUVH5AW4Z3GMOB67WP44LYLEVM2MP3ZEPKFHUB5J47A2J6TUQ", txid)
   116  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   117  }
   118  
   119  func TestMakeKeyRegTxn(t *testing.T) {
   120  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   121  	tx, err := MakeKeyRegTxn(addr, 10, 322575, 323575, []byte{45, 67}, "", "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
   122  		"Kv7QI7chi1y6axoy+t7wzAVpePqRq/rkjzWh/RMYyLo=", "bPgrv4YogPcdaUAxrt1QysYZTVyRAuUMD4zQmCu9llc=", 10000, 10111, 11)
   123  	require.NoError(t, err)
   124  
   125  	a, err := types.DecodeAddress(addr)
   126  	require.NoError(t, err)
   127  	expKeyRegTxn := types.Transaction{
   128  		Type: types.KeyRegistrationTx,
   129  		Header: types.Header{
   130  			Sender:      a,
   131  			Fee:         3060,
   132  			FirstValid:  322575,
   133  			LastValid:   323575,
   134  			Note:        []byte{45, 67},
   135  			GenesisHash: byte32ArrayFromBase64("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="),
   136  			GenesisID:   "",
   137  		},
   138  		KeyregTxnFields: types.KeyregTxnFields{
   139  			VotePK:          byte32ArrayFromBase64("Kv7QI7chi1y6axoy+t7wzAVpePqRq/rkjzWh/RMYyLo="),
   140  			SelectionPK:     byte32ArrayFromBase64("bPgrv4YogPcdaUAxrt1QysYZTVyRAuUMD4zQmCu9llc="),
   141  			VoteFirst:       10000,
   142  			VoteLast:        10111,
   143  			VoteKeyDilution: 11,
   144  		},
   145  	}
   146  	require.Equal(t, expKeyRegTxn, tx)
   147  }
   148  
   149  func TestMakeAssetCreateTxn(t *testing.T) {
   150  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   151  	const defaultFrozen = false
   152  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   153  	const total = 100
   154  	const reserve = addr
   155  	const freeze = addr
   156  	const clawback = addr
   157  	const unitName = "tst"
   158  	const assetName = "testcoin"
   159  	const testURL = "websitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsitewebsi" //96 characters
   160  	const metadataHash = "fACPO4nRgO55j1ndAK3W6Sgc4APkcyFh"
   161  	tx, err := MakeAssetCreateTxn(addr, 10, 322575, 323575, nil, "", genesisHash, total, 0, defaultFrozen, addr, reserve, freeze, clawback, unitName, assetName, testURL, metadataHash)
   162  	require.NoError(t, err)
   163  
   164  	a, err := types.DecodeAddress(addr)
   165  	require.NoError(t, err)
   166  	expectedAssetCreationTxn := types.Transaction{
   167  		Type: types.AssetConfigTx,
   168  		Header: types.Header{
   169  			Sender:      a,
   170  			Fee:         4920,
   171  			FirstValid:  322575,
   172  			LastValid:   323575,
   173  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   174  			GenesisID:   "",
   175  		},
   176  	}
   177  	expectedAssetCreationTxn.AssetParams = types.AssetParams{
   178  		Total:         total,
   179  		DefaultFrozen: defaultFrozen,
   180  		Manager:       a,
   181  		Reserve:       a,
   182  		Freeze:        a,
   183  		Clawback:      a,
   184  		UnitName:      unitName,
   185  		AssetName:     assetName,
   186  		URL:           testURL,
   187  	}
   188  	copy(expectedAssetCreationTxn.AssetParams.MetadataHash[:], []byte(metadataHash))
   189  	require.Equal(t, expectedAssetCreationTxn, tx)
   190  
   191  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   192  	private, err := mnemonic.ToPrivateKey(addrSK)
   193  	require.NoError(t, err)
   194  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   195  	signedGolden := "gqNzaWfEQCPNXED15sdMwiSxl9K4LALy5brxBpnOtBurPK2TAtjXpxKQqN9flVtjxP0GGYVUjNx/Sez0W4v1CSU9FhYSUgOjdHhuh6RhcGFyiaJhbcQgZkFDUE80blJnTzU1ajFuZEFLM1c2U2djNEFQa2N5RmiiYW6odGVzdGNvaW6iYXXZYHdlYnNpdGV3ZWJzaXRld2Vic2l0ZXdlYnNpdGV3ZWJzaXRld2Vic2l0ZXdlYnNpdGV3ZWJzaXRld2Vic2l0ZXdlYnNpdGV3ZWJzaXRld2Vic2l0ZXdlYnNpdGV3ZWJzaaFjxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFmxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFtxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFyxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aF0ZKJ1bqN0c3SjZmVlzRM4omZ2zgAE7A+iZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgAE7/ejc25kxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aR0eXBlpGFjZmc="
   196  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   197  }
   198  
   199  func TestMakeAssetCreateTxnWithDecimals(t *testing.T) {
   200  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   201  	const defaultFrozen = false
   202  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   203  	const total = 100
   204  	const decimals = 1
   205  	const reserve = addr
   206  	const freeze = addr
   207  	const clawback = addr
   208  	const unitName = "tst"
   209  	const assetName = "testcoin"
   210  	const testURL = "website"
   211  	const metadataHash = "fACPO4nRgO55j1ndAK3W6Sgc4APkcyFh"
   212  	tx, err := MakeAssetCreateTxn(addr, 10, 322575, 323575, nil, "", genesisHash, total, decimals, defaultFrozen, addr, reserve, freeze, clawback, unitName, assetName, testURL, metadataHash)
   213  	require.NoError(t, err)
   214  
   215  	a, err := types.DecodeAddress(addr)
   216  	require.NoError(t, err)
   217  	expectedAssetCreationTxn := types.Transaction{
   218  		Type: types.AssetConfigTx,
   219  		Header: types.Header{
   220  			Sender:      a,
   221  			Fee:         4060,
   222  			FirstValid:  322575,
   223  			LastValid:   323575,
   224  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   225  			GenesisID:   "",
   226  		},
   227  	}
   228  	expectedAssetCreationTxn.AssetParams = types.AssetParams{
   229  		Total:         total,
   230  		Decimals:      decimals,
   231  		DefaultFrozen: defaultFrozen,
   232  		Manager:       a,
   233  		Reserve:       a,
   234  		Freeze:        a,
   235  		Clawback:      a,
   236  		UnitName:      unitName,
   237  		AssetName:     assetName,
   238  		URL:           testURL,
   239  	}
   240  	copy(expectedAssetCreationTxn.AssetParams.MetadataHash[:], []byte(metadataHash))
   241  	require.Equal(t, expectedAssetCreationTxn, tx)
   242  
   243  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   244  	private, err := mnemonic.ToPrivateKey(addrSK)
   245  	require.NoError(t, err)
   246  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   247  	signedGolden := "gqNzaWfEQCj5xLqNozR5ahB+LNBlTG+d0gl0vWBrGdAXj1ibsCkvAwOsXs5KHZK1YdLgkdJecQiWm4oiZ+pm5Yg0m3KFqgqjdHhuh6RhcGFyiqJhbcQgZkFDUE80blJnTzU1ajFuZEFLM1c2U2djNEFQa2N5RmiiYW6odGVzdGNvaW6iYXWnd2Vic2l0ZaFjxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aJkYwGhZsQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2hbcQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2hcsQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2hdGSidW6jdHN0o2ZlZc0P3KJmds4ABOwPomdoxCBIY7UYpLPITsgQ8i1PEIHLD3HwWaesIN7GL39w5Qk6IqJsds4ABO/3o3NuZMQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2kdHlwZaRhY2Zn"
   248  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   249  }
   250  
   251  func TestMakeAssetConfigTxn(t *testing.T) {
   252  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   253  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   254  	const manager = addr
   255  	const reserve = addr
   256  	const freeze = addr
   257  	const clawback = addr
   258  	const assetIndex = 1234
   259  	tx, err := MakeAssetConfigTxn(addr, 10, 322575, 323575, nil, "", genesisHash,
   260  		assetIndex, manager, reserve, freeze, clawback, false)
   261  	require.NoError(t, err)
   262  
   263  	a, err := types.DecodeAddress(addr)
   264  	require.NoError(t, err)
   265  	expectedAssetConfigTxn := types.Transaction{
   266  		Type: types.AssetConfigTx,
   267  		Header: types.Header{
   268  			Sender:      a,
   269  			Fee:         3400,
   270  			FirstValid:  322575,
   271  			LastValid:   323575,
   272  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   273  			GenesisID:   "",
   274  		},
   275  	}
   276  
   277  	expectedAssetConfigTxn.AssetParams = types.AssetParams{
   278  		Manager:  a,
   279  		Reserve:  a,
   280  		Freeze:   a,
   281  		Clawback: a,
   282  	}
   283  	expectedAssetConfigTxn.ConfigAsset = types.AssetIndex(assetIndex)
   284  	require.Equal(t, expectedAssetConfigTxn, tx)
   285  
   286  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   287  	private, err := mnemonic.ToPrivateKey(addrSK)
   288  	require.NoError(t, err)
   289  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   290  	signedGolden := "gqNzaWfEQBBkfw5n6UevuIMDo2lHyU4dS80JCCQ/vTRUcTx5m0ivX68zTKyuVRrHaTbxbRRc3YpJ4zeVEnC9Fiw3Wf4REwejdHhuiKRhcGFyhKFjxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFmxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFtxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aFyxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aRjYWlkzQTSo2ZlZc0NSKJmds4ABOwPomdoxCBIY7UYpLPITsgQ8i1PEIHLD3HwWaesIN7GL39w5Qk6IqJsds4ABO/3o3NuZMQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2kdHlwZaRhY2Zn"
   291  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   292  }
   293  
   294  func TestMakeAssetConfigTxnStrictChecking(t *testing.T) {
   295  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   296  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   297  	const manager = addr
   298  	const reserve = addr
   299  	const freeze = ""
   300  	const clawback = addr
   301  	const assetIndex = 1234
   302  	_, err := MakeAssetConfigTxn(addr, 10, 322575, 323575, nil, "", genesisHash,
   303  		assetIndex, manager, reserve, freeze, clawback, true)
   304  	require.Error(t, err)
   305  }
   306  
   307  func TestMakeAssetDestroyTxn(t *testing.T) {
   308  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   309  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   310  	const creator = addr
   311  	const assetIndex = 1
   312  	const firstValidRound = 322575
   313  	const lastValidRound = 323575
   314  	tx, err := MakeAssetDestroyTxn(creator, 10, firstValidRound, lastValidRound, nil, "", genesisHash, assetIndex)
   315  	require.NoError(t, err)
   316  
   317  	a, err := types.DecodeAddress(creator)
   318  	require.NoError(t, err)
   319  
   320  	expectedAssetDestroyTxn := types.Transaction{
   321  		Type: types.AssetConfigTx,
   322  		Header: types.Header{
   323  			Sender:      a,
   324  			Fee:         1880,
   325  			FirstValid:  firstValidRound,
   326  			LastValid:   lastValidRound,
   327  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   328  			GenesisID:   "",
   329  		},
   330  	}
   331  	expectedAssetDestroyTxn.AssetParams = types.AssetParams{}
   332  	expectedAssetDestroyTxn.ConfigAsset = types.AssetIndex(assetIndex)
   333  	require.Equal(t, expectedAssetDestroyTxn, tx)
   334  
   335  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   336  	private, err := mnemonic.ToPrivateKey(addrSK)
   337  	require.NoError(t, err)
   338  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   339  	signedGolden := "gqNzaWfEQBSP7HtzD/Lvn4aVvaNpeR4T93dQgo4LvywEwcZgDEoc/WVl3aKsZGcZkcRFoiWk8AidhfOZzZYutckkccB8RgGjdHhuh6RjYWlkAaNmZWXNB1iiZnbOAATsD6JnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAATv96NzbmTEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9pHR5cGWkYWNmZw=="
   340  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   341  }
   342  
   343  func TestMakeAssetFreezeTxn(t *testing.T) {
   344  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   345  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   346  	const assetIndex = 1
   347  	const firstValidRound = 322575
   348  	const lastValidRound = 323576
   349  	const freezeSetting = true
   350  	const target = addr
   351  	tx, err := MakeAssetFreezeTxn(addr, 10, firstValidRound, lastValidRound, nil, "", genesisHash, assetIndex, target, freezeSetting)
   352  	require.NoError(t, err)
   353  
   354  	a, err := types.DecodeAddress(addr)
   355  	require.NoError(t, err)
   356  
   357  	expectedAssetFreezeTxn := types.Transaction{
   358  		Type: types.AssetFreezeTx,
   359  		Header: types.Header{
   360  			Sender:      a,
   361  			Fee:         2330,
   362  			FirstValid:  firstValidRound,
   363  			LastValid:   lastValidRound,
   364  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   365  			GenesisID:   "",
   366  		},
   367  	}
   368  	expectedAssetFreezeTxn.FreezeAsset = types.AssetIndex(assetIndex)
   369  	expectedAssetFreezeTxn.AssetFrozen = freezeSetting
   370  	expectedAssetFreezeTxn.FreezeAccount = a
   371  	require.Equal(t, expectedAssetFreezeTxn, tx)
   372  
   373  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   374  	private, err := mnemonic.ToPrivateKey(addrSK)
   375  	require.NoError(t, err)
   376  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   377  	signedGolden := "gqNzaWfEQAhru5V2Xvr19s4pGnI0aslqwY4lA2skzpYtDTAN9DKSH5+qsfQQhm4oq+9VHVj7e1rQC49S28vQZmzDTVnYDQGjdHhuiaRhZnJ6w6RmYWRkxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aRmYWlkAaNmZWXNCRqiZnbOAATsD6JnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAATv+KNzbmTEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9pHR5cGWkYWZyeg=="
   378  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   379  }
   380  
   381  func TestMakeAssetTransferTxn(t *testing.T) {
   382  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   383  	private, err := mnemonic.ToPrivateKey(addrSK)
   384  	require.NoError(t, err)
   385  
   386  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   387  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   388  	const sender, recipient, closeAssetsTo = addr, addr, addr
   389  	const assetIndex = 1
   390  	const firstValidRound = 322575
   391  	const lastValidRound = 323576
   392  	const amountToSend = 1
   393  
   394  	tx, err := MakeAssetTransferTxn(sender, recipient, closeAssetsTo, amountToSend, 10, firstValidRound,
   395  		lastValidRound, nil, "", genesisHash, assetIndex)
   396  	require.NoError(t, err)
   397  
   398  	sendAddr, err := types.DecodeAddress(sender)
   399  	require.NoError(t, err)
   400  
   401  	expectedAssetTransferTxn := types.Transaction{
   402  		Type: types.AssetTransferTx,
   403  		Header: types.Header{
   404  			Sender:      sendAddr,
   405  			Fee:         2750,
   406  			FirstValid:  firstValidRound,
   407  			LastValid:   lastValidRound,
   408  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   409  			GenesisID:   "",
   410  		},
   411  	}
   412  
   413  	expectedAssetID := types.AssetIndex(assetIndex)
   414  	expectedAssetTransferTxn.XferAsset = expectedAssetID
   415  
   416  	receiveAddr, err := types.DecodeAddress(recipient)
   417  	require.NoError(t, err)
   418  	expectedAssetTransferTxn.AssetReceiver = receiveAddr
   419  
   420  	closeAddr, err := types.DecodeAddress(closeAssetsTo)
   421  	require.NoError(t, err)
   422  	expectedAssetTransferTxn.AssetCloseTo = closeAddr
   423  
   424  	expectedAssetTransferTxn.AssetAmount = amountToSend
   425  
   426  	require.Equal(t, expectedAssetTransferTxn, tx)
   427  
   428  	// now compare tx against a golden
   429  	const signedGolden = "gqNzaWfEQNkEs3WdfFq6IQKJdF1n0/hbV9waLsvojy9pM1T4fvwfMNdjGQDy+LeesuQUfQVTneJD4VfMP7zKx4OUlItbrwSjdHhuiqRhYW10AaZhY2xvc2XEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9pGFyY3bEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9o2ZlZc0KvqJmds4ABOwPomdoxCBIY7UYpLPITsgQ8i1PEIHLD3HwWaesIN7GL39w5Qk6IqJsds4ABO/4o3NuZMQgCfvSdiwI+Gxa5r9t16epAd5mdddQ4H6MXHaYZH224f2kdHlwZaVheGZlcqR4YWlkAQ=="
   430  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   431  	require.NoError(t, err)
   432  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   433  }
   434  
   435  func TestMakeAssetAcceptanceTxn(t *testing.T) {
   436  	const sender = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   437  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   438  	const assetIndex = 1
   439  	const firstValidRound = 322575
   440  	const lastValidRound = 323575
   441  
   442  	tx, err := MakeAssetAcceptanceTxn(sender, 10, firstValidRound,
   443  		lastValidRound, nil, "", genesisHash, assetIndex)
   444  	require.NoError(t, err)
   445  
   446  	sendAddr, err := types.DecodeAddress(sender)
   447  	require.NoError(t, err)
   448  
   449  	expectedAssetAcceptanceTxn := types.Transaction{
   450  		Type: types.AssetTransferTx,
   451  		Header: types.Header{
   452  			Sender:      sendAddr,
   453  			Fee:         2280,
   454  			FirstValid:  firstValidRound,
   455  			LastValid:   lastValidRound,
   456  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   457  			GenesisID:   "",
   458  		},
   459  	}
   460  
   461  	expectedAssetID := types.AssetIndex(assetIndex)
   462  	expectedAssetAcceptanceTxn.XferAsset = expectedAssetID
   463  	expectedAssetAcceptanceTxn.AssetReceiver = sendAddr
   464  	expectedAssetAcceptanceTxn.AssetAmount = 0
   465  
   466  	require.Equal(t, expectedAssetAcceptanceTxn, tx)
   467  
   468  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   469  	private, err := mnemonic.ToPrivateKey(addrSK)
   470  	require.NoError(t, err)
   471  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   472  	signedGolden := "gqNzaWfEQJ7q2rOT8Sb/wB0F87ld+1zMprxVlYqbUbe+oz0WM63FctIi+K9eYFSqT26XBZ4Rr3+VTJpBE+JLKs8nctl9hgijdHhuiKRhcmN2xCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aNmZWXNCOiiZnbOAATsD6JnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAATv96NzbmTEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9pHR5cGWlYXhmZXKkeGFpZAE="
   473  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   474  }
   475  
   476  func TestMakeAssetRevocationTransaction(t *testing.T) {
   477  	const addr = "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4"
   478  	const genesisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
   479  	const revoker, recipient, revoked = addr, addr, addr
   480  	const assetIndex = 1
   481  	const firstValidRound = 322575
   482  	const lastValidRound = 323575
   483  	const amountToSend = 1
   484  
   485  	tx, err := MakeAssetRevocationTxn(revoker, revoked, recipient, amountToSend, 10, firstValidRound,
   486  		lastValidRound, nil, "", genesisHash, assetIndex)
   487  	require.NoError(t, err)
   488  
   489  	sendAddr, err := types.DecodeAddress(revoker)
   490  	require.NoError(t, err)
   491  
   492  	expectedAssetRevocationTxn := types.Transaction{
   493  		Type: types.AssetTransferTx,
   494  		Header: types.Header{
   495  			Sender:      sendAddr,
   496  			Fee:         2730,
   497  			FirstValid:  firstValidRound,
   498  			LastValid:   lastValidRound,
   499  			GenesisHash: byte32ArrayFromBase64(genesisHash),
   500  			GenesisID:   "",
   501  		},
   502  	}
   503  
   504  	expectedAssetID := types.AssetIndex(assetIndex)
   505  	expectedAssetRevocationTxn.XferAsset = expectedAssetID
   506  
   507  	receiveAddr, err := types.DecodeAddress(recipient)
   508  	require.NoError(t, err)
   509  	expectedAssetRevocationTxn.AssetReceiver = receiveAddr
   510  
   511  	expectedAssetRevocationTxn.AssetAmount = amountToSend
   512  
   513  	targetAddr, err := types.DecodeAddress(revoked)
   514  	require.NoError(t, err)
   515  	expectedAssetRevocationTxn.AssetSender = targetAddr
   516  
   517  	require.Equal(t, expectedAssetRevocationTxn, tx)
   518  
   519  	const addrSK = "awful drop leaf tennis indoor begin mandate discover uncle seven only coil atom any hospital uncover make any climb actor armed measure need above hundred"
   520  	private, err := mnemonic.ToPrivateKey(addrSK)
   521  	require.NoError(t, err)
   522  	_, newStxBytes, err := crypto.SignTransaction(private, tx)
   523  	signedGolden := "gqNzaWfEQHsgfEAmEHUxLLLR9s+Y/yq5WeoGo/jAArCbany+7ZYwExMySzAhmV7M7S8+LBtJalB4EhzEUMKmt3kNKk6+vAWjdHhuiqRhYW10AaRhcmN2xCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aRhc25kxCAJ+9J2LAj4bFrmv23Xp6kB3mZ111Dgfoxcdphkfbbh/aNmZWXNCqqiZnbOAATsD6JnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAATv96NzbmTEIAn70nYsCPhsWua/bdenqQHeZnXXUOB+jFx2mGR9tuH9pHR5cGWlYXhmZXKkeGFpZAE="
   524  	require.EqualValues(t, newStxBytes, byteFromBase64(signedGolden))
   525  }
   526  
   527  func TestComputeGroupID(t *testing.T) {
   528  	// compare regular transactions created in SDK with 'goal clerk send' result
   529  	// compare transaction group created in SDK with 'goal clerk group' result
   530  	const address = "UPYAFLHSIPMJOHVXU2MPLQ46GXJKSDCEMZ6RLCQ7GWB5PRDKJUWKKXECXI"
   531  	const fromAddress, toAddress = address, address
   532  	const fee = 1000
   533  	const amount = 2000
   534  	const genesisID = "devnet-v1.0"
   535  	genesisHash := byteFromBase64("sC3P7e2SdbqKJK0tbiCdK9tdSpbe6XeCGKdoNzmlj0E=")
   536  
   537  	const firstRound1 = 710399
   538  	note1 := byteFromBase64("wRKw5cJ0CMo=")
   539  	tx1, err := MakePaymentTxnWithFlatFee(
   540  		fromAddress, toAddress, fee, amount, firstRound1, firstRound1+1000,
   541  		note1, "", genesisID, genesisHash,
   542  	)
   543  	require.NoError(t, err)
   544  
   545  	const firstRound2 = 710515
   546  	note2 := byteFromBase64("dBlHI6BdrIg=")
   547  	tx2, err := MakePaymentTxnWithFlatFee(
   548  		fromAddress, toAddress, fee, amount, firstRound2, firstRound2+1000,
   549  		note2, "", genesisID, genesisHash,
   550  	)
   551  	require.NoError(t, err)
   552  
   553  	const goldenTx1 = "gaN0eG6Ko2FtdM0H0KNmZWXNA+iiZnbOAArW/6NnZW6rZGV2bmV0LXYxLjCiZ2jEILAtz+3tknW6iiStLW4gnSvbXUqW3ul3ghinaDc5pY9Bomx2zgAK2uekbm90ZcQIwRKw5cJ0CMqjcmN2xCCj8AKs8kPYlx63ppj1w5410qkMRGZ9FYofNYPXxGpNLKNzbmTEIKPwAqzyQ9iXHremmPXDnjXSqQxEZn0Vih81g9fEak0spHR5cGWjcGF5"
   554  	const goldenTx2 = "gaN0eG6Ko2FtdM0H0KNmZWXNA+iiZnbOAArXc6NnZW6rZGV2bmV0LXYxLjCiZ2jEILAtz+3tknW6iiStLW4gnSvbXUqW3ul3ghinaDc5pY9Bomx2zgAK21ukbm90ZcQIdBlHI6BdrIijcmN2xCCj8AKs8kPYlx63ppj1w5410qkMRGZ9FYofNYPXxGpNLKNzbmTEIKPwAqzyQ9iXHremmPXDnjXSqQxEZn0Vih81g9fEak0spHR5cGWjcGF5"
   555  
   556  	// goal clerk send dumps unsigned transaction as signed with empty signature in order to save tx type
   557  	stx1 := types.SignedTxn{Sig: types.Signature{}, Msig: types.MultisigSig{}, Txn: tx1}
   558  	stx2 := types.SignedTxn{Sig: types.Signature{}, Msig: types.MultisigSig{}, Txn: tx2}
   559  	require.Equal(t, byteFromBase64(goldenTx1), msgpack.Encode(stx1))
   560  	require.Equal(t, byteFromBase64(goldenTx2), msgpack.Encode(stx2))
   561  
   562  	gid, err := crypto.ComputeGroupID([]types.Transaction{tx1, tx2})
   563  
   564  	// goal clerk group sets Group to every transaction and concatenate them in output file
   565  	// simulating that behavior here
   566  	stx1.Txn.Group = gid
   567  	stx2.Txn.Group = gid
   568  
   569  	var txg []byte
   570  	txg = append(txg, msgpack.Encode(stx1)...)
   571  	txg = append(txg, msgpack.Encode(stx2)...)
   572  
   573  	const goldenTxg = "gaN0eG6Lo2FtdM0H0KNmZWXNA+iiZnbOAArW/6NnZW6rZGV2bmV0LXYxLjCiZ2jEILAtz+3tknW6iiStLW4gnSvbXUqW3ul3ghinaDc5pY9Bo2dycMQgLiQ9OBup9H/bZLSfQUH2S6iHUM6FQ3PLuv9FNKyt09SibHbOAAra56Rub3RlxAjBErDlwnQIyqNyY3bEIKPwAqzyQ9iXHremmPXDnjXSqQxEZn0Vih81g9fEak0so3NuZMQgo/ACrPJD2Jcet6aY9cOeNdKpDERmfRWKHzWD18RqTSykdHlwZaNwYXmBo3R4boujYW10zQfQo2ZlZc0D6KJmds4ACtdzo2dlbqtkZXZuZXQtdjEuMKJnaMQgsC3P7e2SdbqKJK0tbiCdK9tdSpbe6XeCGKdoNzmlj0GjZ3JwxCAuJD04G6n0f9tktJ9BQfZLqIdQzoVDc8u6/0U0rK3T1KJsds4ACttbpG5vdGXECHQZRyOgXayIo3JjdsQgo/ACrPJD2Jcet6aY9cOeNdKpDERmfRWKHzWD18RqTSyjc25kxCCj8AKs8kPYlx63ppj1w5410qkMRGZ9FYofNYPXxGpNLKR0eXBlo3BheQ=="
   574  
   575  	require.Equal(t, byteFromBase64(goldenTxg), txg)
   576  
   577  	// check AssignGroupID, do not validate correctness of Group field calculation
   578  	result, err := AssignGroupID([]types.Transaction{tx1, tx2}, "BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4")
   579  	require.NoError(t, err)
   580  	require.Equal(t, 0, len(result))
   581  
   582  	result, err = AssignGroupID([]types.Transaction{tx1, tx2}, address)
   583  	require.NoError(t, err)
   584  	require.Equal(t, 2, len(result))
   585  
   586  	result, err = AssignGroupID([]types.Transaction{tx1, tx2}, "")
   587  	require.NoError(t, err)
   588  	require.Equal(t, 2, len(result))
   589  }
   590  
   591  func TestLogicSig(t *testing.T) {
   592  	// validate LogicSig signed transaction against goal
   593  	const fromAddress = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU"
   594  	const toAddress = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI"
   595  	const referenceTxID = "5FJDJD5LMZC3EHUYYJNH5I23U4X6H2KXABNDGPIL557ZMJ33GZHQ"
   596  	const mn = "advice pudding treat near rule blouse same whisper inner electric quit surface sunny dismiss leader blood seat clown cost exist hospital century reform able sponsor"
   597  	const fee = 1000
   598  	const amount = 2000
   599  	const firstRound = 2063137
   600  	const genesisID = "devnet-v1.0"
   601  	genesisHash := byteFromBase64("sC3P7e2SdbqKJK0tbiCdK9tdSpbe6XeCGKdoNzmlj0E=")
   602  	note := byteFromBase64("8xMCTuLQ810=")
   603  
   604  	tx, err := MakePaymentTxnWithFlatFee(
   605  		fromAddress, toAddress, fee, amount, firstRound, firstRound+1000,
   606  		note, "", genesisID, genesisHash,
   607  	)
   608  	require.NoError(t, err)
   609  
   610  	// goal clerk send -o tx3 -a 2000 --fee 1000 -d ~/.algorand -w test -L sig.lsig --argb64 MTIz --argb64 NDU2 \
   611  	// -f 47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU \
   612  	// -t PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI
   613  	const golden = "gqRsc2lng6NhcmeSxAMxMjPEAzQ1NqFsxAUBIAEBIqNzaWfEQE6HXaI5K0lcq50o/y3bWOYsyw9TLi/oorZB4xaNdn1Z14351u2f6JTON478fl+JhIP4HNRRAIh/I8EWXBPpJQ2jdHhuiqNhbXTNB9CjZmVlzQPoomZ2zgAfeyGjZ2Vuq2Rldm5ldC12MS4womdoxCCwLc/t7ZJ1uookrS1uIJ0r211Klt7pd4IYp2g3OaWPQaJsds4AH38JpG5vdGXECPMTAk7i0PNdo3JjdsQge2ziT+tbrMCxZOKcIixX9fY9w4fUOQSCWEEcX+EPfAKjc25kxCDn8PhNBoEd+fMcjYeLEVX0Zx1RoYXCAJCGZ/RJWHBooaR0eXBlo3BheQ=="
   614  
   615  	program := []byte{1, 32, 1, 1, 34}
   616  	args := make([][]byte, 2)
   617  	args[0] = []byte("123")
   618  	args[1] = []byte("456")
   619  	key, err := mnemonic.ToPrivateKey(mn)
   620  	var pk crypto.MultisigAccount
   621  	require.NoError(t, err)
   622  	lsig, err := crypto.MakeLogicSig(program, args, key, pk)
   623  	require.NoError(t, err)
   624  
   625  	_, stxBytes, err := crypto.SignLogicsigTransaction(lsig, tx)
   626  	require.NoError(t, err)
   627  
   628  	require.Equal(t, byteFromBase64(golden), stxBytes)
   629  
   630  	sender, err := types.DecodeAddress(fromAddress)
   631  	require.NoError(t, err)
   632  
   633  	verified := crypto.VerifyLogicSig(lsig, sender)
   634  	require.True(t, verified)
   635  
   636  }