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 }