github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/stdlib/contract_test.go (about) 1 package stdlib_test 2 3 import ( 4 "encoding/binary" 5 "encoding/hex" 6 "math/big" 7 "strings" 8 "testing" 9 10 "github.com/onflow/cadence" 11 "github.com/onflow/cadence/encoding/json" 12 "github.com/onflow/cadence/runtime" 13 "github.com/onflow/cadence/runtime/common" 14 "github.com/onflow/cadence/runtime/sema" 15 cadenceStdlib "github.com/onflow/cadence/runtime/stdlib" 16 "github.com/onflow/cadence/runtime/tests/utils" 17 coreContracts "github.com/onflow/flow-core-contracts/lib/go/contracts" 18 coreContractstemplates "github.com/onflow/flow-core-contracts/lib/go/templates" 19 "github.com/onflow/go-ethereum/crypto" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 23 "github.com/onflow/flow-go/fvm/blueprints" 24 "github.com/onflow/flow-go/fvm/environment" 25 "github.com/onflow/flow-go/fvm/evm/stdlib" 26 . "github.com/onflow/flow-go/fvm/evm/testutils" 27 "github.com/onflow/flow-go/fvm/evm/types" 28 "github.com/onflow/flow-go/model/flow" 29 ) 30 31 type testContractHandler struct { 32 flowTokenAddress common.Address 33 evmContractAddress common.Address 34 deployCOA func(uint64) types.Address 35 accountByAddress func(types.Address, bool) types.Account 36 lastExecutedBlock func() *types.Block 37 run func(tx []byte, coinbase types.Address) *types.ResultSummary 38 batchRun func(txs [][]byte, coinbase types.Address) []*types.ResultSummary 39 generateResourceUUID func() uint64 40 dryRun func(tx []byte, from types.Address) *types.ResultSummary 41 } 42 43 var _ types.ContractHandler = &testContractHandler{} 44 45 func (t *testContractHandler) FlowTokenAddress() common.Address { 46 return t.flowTokenAddress 47 } 48 49 func (t *testContractHandler) EVMContractAddress() common.Address { 50 return t.evmContractAddress 51 } 52 53 func (t *testContractHandler) DeployCOA(uuid uint64) types.Address { 54 if t.deployCOA == nil { 55 var address types.Address 56 binary.LittleEndian.PutUint64(address[:], uuid) 57 return address 58 } 59 return t.deployCOA(uuid) 60 } 61 62 func (t *testContractHandler) AccountByAddress(addr types.Address, isAuthorized bool) types.Account { 63 if t.accountByAddress == nil { 64 panic("unexpected AccountByAddress") 65 } 66 return t.accountByAddress(addr, isAuthorized) 67 } 68 69 func (t *testContractHandler) LastExecutedBlock() *types.Block { 70 if t.lastExecutedBlock == nil { 71 panic("unexpected LastExecutedBlock") 72 } 73 return t.lastExecutedBlock() 74 } 75 76 func (t *testContractHandler) Run(tx []byte, coinbase types.Address) *types.ResultSummary { 77 if t.run == nil { 78 panic("unexpected Run") 79 } 80 return t.run(tx, coinbase) 81 } 82 83 func (t *testContractHandler) DryRun(tx []byte, from types.Address) *types.ResultSummary { 84 if t.dryRun == nil { 85 panic("unexpected DryRun") 86 } 87 return t.dryRun(tx, from) 88 } 89 90 func (t *testContractHandler) BatchRun(txs [][]byte, coinbase types.Address) []*types.ResultSummary { 91 if t.batchRun == nil { 92 panic("unexpected BatchRun") 93 } 94 return t.batchRun(txs, coinbase) 95 } 96 97 func (t *testContractHandler) GenerateResourceUUID() uint64 { 98 if t.generateResourceUUID == nil { 99 panic("unexpected GenerateResourceUUID") 100 } 101 return t.generateResourceUUID() 102 } 103 104 type testFlowAccount struct { 105 address types.Address 106 balance func() types.Balance 107 code func() types.Code 108 codeHash func() []byte 109 nonce func() uint64 110 transfer func(address types.Address, balance types.Balance) 111 deposit func(vault *types.FLOWTokenVault) 112 withdraw func(balance types.Balance) *types.FLOWTokenVault 113 deploy func(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary 114 call func(address types.Address, data types.Data, limit types.GasLimit, balance types.Balance) *types.ResultSummary 115 } 116 117 var _ types.Account = &testFlowAccount{} 118 119 func (t *testFlowAccount) Address() types.Address { 120 return t.address 121 } 122 123 func (t *testFlowAccount) Balance() types.Balance { 124 if t.balance == nil { 125 return types.NewBalanceFromUFix64(0) 126 } 127 return t.balance() 128 } 129 130 func (t *testFlowAccount) Code() types.Code { 131 if t.code == nil { 132 return types.Code{} 133 } 134 return t.code() 135 } 136 137 func (t *testFlowAccount) CodeHash() []byte { 138 if t.codeHash == nil { 139 return nil 140 } 141 return t.codeHash() 142 } 143 144 func (t *testFlowAccount) Nonce() uint64 { 145 if t.nonce == nil { 146 return 0 147 } 148 return t.nonce() 149 } 150 151 func (t *testFlowAccount) Transfer(address types.Address, balance types.Balance) { 152 if t.transfer == nil { 153 panic("unexpected Transfer") 154 } 155 t.transfer(address, balance) 156 } 157 158 func (t *testFlowAccount) Deposit(vault *types.FLOWTokenVault) { 159 if t.deposit == nil { 160 panic("unexpected Deposit") 161 } 162 t.deposit(vault) 163 } 164 165 func (t *testFlowAccount) Withdraw(balance types.Balance) *types.FLOWTokenVault { 166 if t.withdraw == nil { 167 panic("unexpected Withdraw") 168 } 169 return t.withdraw(balance) 170 } 171 172 func (t *testFlowAccount) Deploy(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary { 173 if t.deploy == nil { 174 panic("unexpected Deploy") 175 } 176 return t.deploy(code, limit, balance) 177 } 178 179 func (t *testFlowAccount) Call(address types.Address, data types.Data, limit types.GasLimit, balance types.Balance) *types.ResultSummary { 180 if t.call == nil { 181 panic("unexpected Call") 182 } 183 return t.call(address, data, limit, balance) 184 } 185 186 func requireEqualEventAddress(t *testing.T, event cadence.Event, address types.Address) { 187 actual := cadence.SearchFieldByName(event, types.CadenceOwnedAccountCreatedTypeAddressFieldName) 188 strippedHex := strings.TrimPrefix(address.String(), "0x") 189 expected, err := cadence.NewString(strippedHex) 190 if err != nil { 191 require.NoError(t, err) 192 } 193 require.Equal(t, expected, actual) 194 } 195 196 func deployContracts( 197 t *testing.T, 198 rt runtime.Runtime, 199 contractsAddress flow.Address, 200 runtimeInterface *TestRuntimeInterface, 201 transactionEnvironment runtime.Environment, 202 nextTransactionLocation func() common.TransactionLocation, 203 ) { 204 205 contractsAddressHex := contractsAddress.Hex() 206 207 env := coreContractstemplates.Environment{ 208 ServiceAccountAddress: contractsAddressHex, 209 ViewResolverAddress: contractsAddressHex, 210 BurnerAddress: contractsAddressHex, 211 FungibleTokenAddress: contractsAddressHex, 212 NonFungibleTokenAddress: contractsAddressHex, 213 MetadataViewsAddress: contractsAddressHex, 214 FungibleTokenMetadataViewsAddress: contractsAddressHex, 215 } 216 217 contracts := []struct { 218 name string 219 code []byte 220 deployTx []byte 221 }{ 222 { 223 name: "ViewResolver", 224 code: coreContracts.ViewResolver(), 225 }, 226 { 227 name: "Burner", 228 code: coreContracts.Burner(), 229 }, 230 { 231 name: "FungibleToken", 232 code: coreContracts.FungibleToken( 233 env, 234 ), 235 }, 236 { 237 name: "NonFungibleToken", 238 code: coreContracts.NonFungibleToken( 239 env, 240 ), 241 }, 242 { 243 name: "MetadataViews", 244 code: coreContracts.MetadataViews( 245 env, 246 ), 247 }, 248 { 249 name: "FungibleTokenMetadataViews", 250 code: coreContracts.FungibleTokenMetadataViews( 251 env, 252 ), 253 }, 254 { 255 name: "FlowToken", 256 code: coreContracts.FlowToken( 257 env, 258 ), 259 deployTx: []byte(` 260 transaction(name: String, code: String) { 261 prepare(signer: auth(AddContract, Storage, Capabilities) &Account) { 262 signer.contracts.add(name: name, code: code.utf8, signer) 263 } 264 } 265 `), 266 }, 267 { 268 name: stdlib.ContractName, 269 code: stdlib.ContractCode(contractsAddress, contractsAddress, contractsAddress), 270 }, 271 } 272 273 for _, contract := range contracts { 274 275 deployTx := contract.deployTx 276 if len(deployTx) == 0 { 277 deployTx = blueprints.DeployContractTransactionTemplate 278 } 279 280 err := rt.ExecuteTransaction( 281 runtime.Script{ 282 Source: deployTx, 283 Arguments: EncodeArgs([]cadence.Value{ 284 cadence.String(contract.name), 285 cadence.String(contract.code), 286 }), 287 }, 288 runtime.Context{ 289 Interface: runtimeInterface, 290 Environment: transactionEnvironment, 291 Location: nextTransactionLocation(), 292 }, 293 ) 294 require.NoError(t, err) 295 } 296 297 } 298 299 func newEVMTransactionEnvironment(handler types.ContractHandler, contractAddress flow.Address) runtime.Environment { 300 transactionEnvironment := runtime.NewBaseInterpreterEnvironment(runtime.Config{}) 301 302 stdlib.SetupEnvironment( 303 transactionEnvironment, 304 handler, 305 contractAddress, 306 ) 307 308 return transactionEnvironment 309 } 310 311 func newEVMScriptEnvironment(handler types.ContractHandler, contractAddress flow.Address) runtime.Environment { 312 scriptEnvironment := runtime.NewScriptInterpreterEnvironment(runtime.Config{}) 313 314 stdlib.SetupEnvironment( 315 scriptEnvironment, 316 handler, 317 contractAddress, 318 ) 319 320 return scriptEnvironment 321 } 322 323 func TestEVMEncodeABI(t *testing.T) { 324 325 t.Parallel() 326 327 handler := &testContractHandler{} 328 329 contractsAddress := flow.BytesToAddress([]byte{0x1}) 330 331 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 332 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 333 334 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 335 336 script := []byte(` 337 import EVM from 0x1 338 339 access(all) 340 fun main(): [UInt8] { 341 return EVM.encodeABI(["John Doe", UInt64(33), false]) 342 } 343 `) 344 345 accountCodes := map[common.Location][]byte{} 346 var events []cadence.Event 347 348 computation := uint(0) 349 runtimeInterface := &TestRuntimeInterface{ 350 Storage: NewTestLedger(nil, nil), 351 OnGetSigningAccounts: func() ([]runtime.Address, error) { 352 return []runtime.Address{runtime.Address(contractsAddress)}, nil 353 }, 354 OnResolveLocation: LocationResolver, 355 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 356 accountCodes[location] = code 357 return nil 358 }, 359 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 360 code = accountCodes[location] 361 return code, nil 362 }, 363 OnEmitEvent: func(event cadence.Event) error { 364 events = append(events, event) 365 return nil 366 }, 367 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 368 return json.Decode(nil, b) 369 }, 370 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 371 if compKind == environment.ComputationKindEVMEncodeABI { 372 computation += intensity 373 } 374 return nil 375 }, 376 } 377 378 nextTransactionLocation := NewTransactionLocationGenerator() 379 nextScriptLocation := NewScriptLocationGenerator() 380 381 // Deploy contracts 382 383 deployContracts( 384 t, 385 rt, 386 contractsAddress, 387 runtimeInterface, 388 transactionEnvironment, 389 nextTransactionLocation, 390 ) 391 392 // Run script 393 394 result, err := rt.ExecuteScript( 395 runtime.Script{ 396 Source: script, 397 Arguments: [][]byte{}, 398 }, 399 runtime.Context{ 400 Interface: runtimeInterface, 401 Environment: scriptEnvironment, 402 Location: nextScriptLocation(), 403 }, 404 ) 405 require.NoError(t, err) 406 407 abiBytes := []byte{ 408 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 409 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 410 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 411 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 412 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 413 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 414 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 415 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 416 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 417 0x0, 0x8, 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x44, 0x6f, 0x65, 0x0, 0x0, 418 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 419 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 420 } 421 cdcBytes := make([]cadence.Value, 0) 422 for _, bt := range abiBytes { 423 cdcBytes = append(cdcBytes, cadence.UInt8(bt)) 424 } 425 encodedABI := cadence.NewArray( 426 cdcBytes, 427 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 428 429 assert.Equal(t, 430 encodedABI, 431 result, 432 ) 433 assert.Equal(t, computation, uint(len(cdcBytes))) 434 } 435 436 func TestEVMEncodeABIComputation(t *testing.T) { 437 438 t.Parallel() 439 440 handler := &testContractHandler{} 441 442 contractsAddress := flow.BytesToAddress([]byte{0x1}) 443 444 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 445 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 446 447 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 448 449 script := []byte(` 450 import EVM from 0x1 451 452 access(all) 453 fun main(): [UInt8] { 454 let address = EVM.EVMAddress( 455 bytes: [ 456 122, 88, 192, 190, 114, 190, 33, 139, 65, 198, 457 8, 183, 254, 124, 91, 182, 48, 115, 108, 113 458 ] 459 ) 460 let arr: [UInt8] = [1, 2, 3, 4, 5] 461 462 return EVM.encodeABI([ 463 "John Doe", 464 UInt64(33), 465 false, 466 address, 467 [arr], 468 ["one", "two", "three"] 469 ]) 470 } 471 `) 472 473 accountCodes := map[common.Location][]byte{} 474 var events []cadence.Event 475 476 computation := uint(0) 477 runtimeInterface := &TestRuntimeInterface{ 478 Storage: NewTestLedger(nil, nil), 479 OnGetSigningAccounts: func() ([]runtime.Address, error) { 480 return []runtime.Address{runtime.Address(contractsAddress)}, nil 481 }, 482 OnResolveLocation: LocationResolver, 483 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 484 accountCodes[location] = code 485 return nil 486 }, 487 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 488 code = accountCodes[location] 489 return code, nil 490 }, 491 OnEmitEvent: func(event cadence.Event) error { 492 events = append(events, event) 493 return nil 494 }, 495 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 496 return json.Decode(nil, b) 497 }, 498 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 499 if compKind == environment.ComputationKindEVMEncodeABI { 500 computation += intensity 501 } 502 return nil 503 }, 504 } 505 506 nextTransactionLocation := NewTransactionLocationGenerator() 507 nextScriptLocation := NewScriptLocationGenerator() 508 509 // Deploy contracts 510 511 deployContracts( 512 t, 513 rt, 514 contractsAddress, 515 runtimeInterface, 516 transactionEnvironment, 517 nextTransactionLocation, 518 ) 519 520 // Run script 521 522 result, err := rt.ExecuteScript( 523 runtime.Script{ 524 Source: script, 525 Arguments: [][]byte{}, 526 }, 527 runtime.Context{ 528 Interface: runtimeInterface, 529 Environment: scriptEnvironment, 530 Location: nextScriptLocation(), 531 }, 532 ) 533 require.NoError(t, err) 534 535 cdcBytes, ok := result.(cadence.Array) 536 require.True(t, ok) 537 // computation & len(cdcBytes.Values) is equal to 832 538 assert.Equal(t, computation, uint(len(cdcBytes.Values))) 539 } 540 541 func TestEVMEncodeABIComputationEmptyDynamicVariables(t *testing.T) { 542 543 t.Parallel() 544 545 handler := &testContractHandler{} 546 547 contractsAddress := flow.BytesToAddress([]byte{0x1}) 548 549 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 550 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 551 552 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 553 554 script := []byte(` 555 import EVM from 0x1 556 557 access(all) 558 fun main(): [UInt8] { 559 return EVM.encodeABI([ 560 "", 561 [[""], [] as [String]], 562 [] as [UInt8], 563 ["", "", ""] 564 ]) 565 } 566 `) 567 568 accountCodes := map[common.Location][]byte{} 569 var events []cadence.Event 570 571 computation := uint(0) 572 runtimeInterface := &TestRuntimeInterface{ 573 Storage: NewTestLedger(nil, nil), 574 OnGetSigningAccounts: func() ([]runtime.Address, error) { 575 return []runtime.Address{runtime.Address(contractsAddress)}, nil 576 }, 577 OnResolveLocation: LocationResolver, 578 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 579 accountCodes[location] = code 580 return nil 581 }, 582 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 583 code = accountCodes[location] 584 return code, nil 585 }, 586 OnEmitEvent: func(event cadence.Event) error { 587 events = append(events, event) 588 return nil 589 }, 590 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 591 return json.Decode(nil, b) 592 }, 593 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 594 if compKind == environment.ComputationKindEVMEncodeABI { 595 computation += intensity 596 } 597 return nil 598 }, 599 } 600 601 nextTransactionLocation := NewTransactionLocationGenerator() 602 nextScriptLocation := NewScriptLocationGenerator() 603 604 // Deploy contracts 605 606 deployContracts( 607 t, 608 rt, 609 contractsAddress, 610 runtimeInterface, 611 transactionEnvironment, 612 nextTransactionLocation, 613 ) 614 615 // Run script 616 617 result, err := rt.ExecuteScript( 618 runtime.Script{ 619 Source: script, 620 Arguments: [][]byte{}, 621 }, 622 runtime.Context{ 623 Interface: runtimeInterface, 624 Environment: scriptEnvironment, 625 Location: nextScriptLocation(), 626 }, 627 ) 628 require.NoError(t, err) 629 630 cdcBytes, ok := result.(cadence.Array) 631 require.True(t, ok) 632 // computation & len(cdcBytes.Values) is equal to 832 633 assert.Equal(t, computation, uint(len(cdcBytes.Values))) 634 } 635 636 func TestEVMEncodeABIComputationDynamicVariablesAboveChunkSize(t *testing.T) { 637 638 t.Parallel() 639 640 handler := &testContractHandler{} 641 642 contractsAddress := flow.BytesToAddress([]byte{0x1}) 643 644 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 645 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 646 647 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 648 649 script := []byte(` 650 import EVM from 0x1 651 652 access(all) 653 fun main(): [UInt8] { 654 let str = "abcdefghijklmnopqrstuvwxyz" 655 let arr: [UInt64] = [ 656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 657 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 658 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 659 ] 660 661 return EVM.encodeABI([ 662 str, 663 str.concat(str).concat(str), 664 [[str]], 665 arr, 666 [arr], 667 arr.concat(arr).concat(arr) 668 ]) 669 } 670 `) 671 672 accountCodes := map[common.Location][]byte{} 673 var events []cadence.Event 674 675 computation := uint(0) 676 runtimeInterface := &TestRuntimeInterface{ 677 Storage: NewTestLedger(nil, nil), 678 OnGetSigningAccounts: func() ([]runtime.Address, error) { 679 return []runtime.Address{runtime.Address(contractsAddress)}, nil 680 }, 681 OnResolveLocation: LocationResolver, 682 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 683 accountCodes[location] = code 684 return nil 685 }, 686 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 687 code = accountCodes[location] 688 return code, nil 689 }, 690 OnEmitEvent: func(event cadence.Event) error { 691 events = append(events, event) 692 return nil 693 }, 694 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 695 return json.Decode(nil, b) 696 }, 697 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 698 if compKind == environment.ComputationKindEVMEncodeABI { 699 computation += intensity 700 } 701 return nil 702 }, 703 } 704 705 nextTransactionLocation := NewTransactionLocationGenerator() 706 nextScriptLocation := NewScriptLocationGenerator() 707 708 // Deploy contracts 709 710 deployContracts( 711 t, 712 rt, 713 contractsAddress, 714 runtimeInterface, 715 transactionEnvironment, 716 nextTransactionLocation, 717 ) 718 719 // Run script 720 721 result, err := rt.ExecuteScript( 722 runtime.Script{ 723 Source: script, 724 Arguments: [][]byte{}, 725 }, 726 runtime.Context{ 727 Interface: runtimeInterface, 728 Environment: scriptEnvironment, 729 Location: nextScriptLocation(), 730 }, 731 ) 732 require.NoError(t, err) 733 734 cdcBytes, ok := result.(cadence.Array) 735 require.True(t, ok) 736 // computation & len(cdcBytes.Values) is equal to 832 737 assert.Equal(t, computation, uint(len(cdcBytes.Values))) 738 } 739 740 func TestEVMDecodeABI(t *testing.T) { 741 742 t.Parallel() 743 744 handler := &testContractHandler{} 745 746 contractsAddress := flow.BytesToAddress([]byte{0x1}) 747 748 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 749 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 750 751 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 752 753 script := []byte(` 754 import EVM from 0x1 755 756 access(all) 757 fun main(data: [UInt8]): Bool { 758 let types = [Type<String>(), Type<UInt64>(), Type<Bool>()] 759 let values = EVM.decodeABI(types: types, data: data) 760 761 assert(values.length == 3) 762 assert((values[0] as! String) == "John Doe") 763 assert((values[1] as! UInt64) == UInt64(33)) 764 assert((values[2] as! Bool) == false) 765 766 return true 767 } 768 `) 769 770 accountCodes := map[common.Location][]byte{} 771 var events []cadence.Event 772 773 computation := uint(0) 774 runtimeInterface := &TestRuntimeInterface{ 775 Storage: NewTestLedger(nil, nil), 776 OnGetSigningAccounts: func() ([]runtime.Address, error) { 777 return []runtime.Address{runtime.Address(contractsAddress)}, nil 778 }, 779 OnResolveLocation: LocationResolver, 780 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 781 accountCodes[location] = code 782 return nil 783 }, 784 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 785 code = accountCodes[location] 786 return code, nil 787 }, 788 OnEmitEvent: func(event cadence.Event) error { 789 events = append(events, event) 790 return nil 791 }, 792 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 793 return json.Decode(nil, b) 794 }, 795 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 796 if compKind == environment.ComputationKindEVMDecodeABI { 797 computation += intensity 798 } 799 return nil 800 }, 801 } 802 803 nextTransactionLocation := NewTransactionLocationGenerator() 804 nextScriptLocation := NewScriptLocationGenerator() 805 806 // Deploy contracts 807 808 deployContracts( 809 t, 810 rt, 811 contractsAddress, 812 runtimeInterface, 813 transactionEnvironment, 814 nextTransactionLocation, 815 ) 816 817 // Run script 818 abiBytes := []byte{ 819 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 820 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 821 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 822 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 823 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 824 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 825 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 826 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 827 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 828 0x0, 0x8, 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x44, 0x6f, 0x65, 0x0, 0x0, 829 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 830 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 831 } 832 cdcBytes := make([]cadence.Value, 0) 833 for _, bt := range abiBytes { 834 cdcBytes = append(cdcBytes, cadence.UInt8(bt)) 835 } 836 encodedABI := cadence.NewArray( 837 cdcBytes, 838 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 839 840 result, err := rt.ExecuteScript( 841 runtime.Script{ 842 Source: script, 843 Arguments: EncodeArgs([]cadence.Value{ 844 encodedABI, 845 }), 846 }, 847 runtime.Context{ 848 Interface: runtimeInterface, 849 Environment: scriptEnvironment, 850 Location: nextScriptLocation(), 851 }, 852 ) 853 require.NoError(t, err) 854 855 assert.Equal(t, cadence.NewBool(true), result) 856 assert.Equal(t, computation, uint(len(cdcBytes))) 857 } 858 859 func TestEVMDecodeABIComputation(t *testing.T) { 860 861 t.Parallel() 862 863 handler := &testContractHandler{} 864 865 contractsAddress := flow.BytesToAddress([]byte{0x1}) 866 867 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 868 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 869 870 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 871 872 script := []byte(` 873 import EVM from 0x1 874 875 access(all) 876 fun main(): [UInt8] { 877 let address = EVM.EVMAddress( 878 bytes: [ 879 122, 88, 192, 190, 114, 190, 33, 139, 65, 198, 880 8, 183, 254, 124, 91, 182, 48, 115, 108, 113 881 ] 882 ) 883 let arr: [UInt8] = [1, 2, 3, 4, 5] 884 885 let data = EVM.encodeABI([ 886 "John Doe", 887 UInt64(33), 888 true, 889 address, 890 [arr], 891 ["one", "two", "three"] 892 ]) 893 894 let types = [ 895 Type<String>(), Type<UInt64>(), Type<Bool>(), Type<EVM.EVMAddress>(), 896 Type<[[UInt8]]>(), Type<[String]>() 897 ] 898 let values = EVM.decodeABI(types: types, data: data) 899 900 return data 901 } 902 `) 903 904 accountCodes := map[common.Location][]byte{} 905 var events []cadence.Event 906 907 computation := uint(0) 908 runtimeInterface := &TestRuntimeInterface{ 909 Storage: NewTestLedger(nil, nil), 910 OnGetSigningAccounts: func() ([]runtime.Address, error) { 911 return []runtime.Address{runtime.Address(contractsAddress)}, nil 912 }, 913 OnResolveLocation: LocationResolver, 914 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 915 accountCodes[location] = code 916 return nil 917 }, 918 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 919 code = accountCodes[location] 920 return code, nil 921 }, 922 OnEmitEvent: func(event cadence.Event) error { 923 events = append(events, event) 924 return nil 925 }, 926 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 927 return json.Decode(nil, b) 928 }, 929 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 930 if compKind == environment.ComputationKindEVMDecodeABI { 931 computation += intensity 932 } 933 return nil 934 }, 935 } 936 937 nextTransactionLocation := NewTransactionLocationGenerator() 938 nextScriptLocation := NewScriptLocationGenerator() 939 940 // Deploy contracts 941 942 deployContracts( 943 t, 944 rt, 945 contractsAddress, 946 runtimeInterface, 947 transactionEnvironment, 948 nextTransactionLocation, 949 ) 950 951 // Run script 952 953 result, err := rt.ExecuteScript( 954 runtime.Script{ 955 Source: script, 956 Arguments: [][]byte{}, 957 }, 958 runtime.Context{ 959 Interface: runtimeInterface, 960 Environment: scriptEnvironment, 961 Location: nextScriptLocation(), 962 }, 963 ) 964 require.NoError(t, err) 965 966 cdcBytes, ok := result.(cadence.Array) 967 require.True(t, ok) 968 // computation & len(cdcBytes.Values) is equal to 832 969 assert.Equal(t, computation, uint(len(cdcBytes.Values))) 970 } 971 972 func TestEVMEncodeDecodeABIRoundtrip(t *testing.T) { 973 974 t.Parallel() 975 976 handler := &testContractHandler{} 977 978 contractsAddress := flow.BytesToAddress([]byte{0x1}) 979 980 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 981 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 982 983 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 984 985 script := []byte(` 986 import EVM from 0x1 987 988 access(all) 989 fun main(): Bool { 990 // Check EVM.EVMAddress encode/decode 991 // bytes for address 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71 992 let address = EVM.EVMAddress( 993 bytes: [ 994 122, 88, 192, 190, 114, 190, 33, 139, 65, 198, 995 8, 183, 254, 124, 91, 182, 48, 115, 108, 113 996 ] 997 ) 998 var data = EVM.encodeABI([address]) 999 var values = EVM.decodeABI(types: [Type<EVM.EVMAddress>()], data: data) 1000 assert(values.length == 1) 1001 assert((values[0] as! EVM.EVMAddress).bytes == address.bytes) 1002 1003 // Check String encode/decode 1004 data = EVM.encodeABI(["John Doe", ""]) 1005 values = EVM.decodeABI(types: [Type<String>(), Type<String>()], data: data) 1006 assert((values[0] as! String) == "John Doe") 1007 assert((values[1] as! String) == "") 1008 1009 // Check Bool encode/decode 1010 data = EVM.encodeABI([true, false]) 1011 values = EVM.decodeABI(types: [Type<Bool>(), Type<Bool>()], data: data) 1012 assert((values[0] as! Bool) == true) 1013 assert((values[1] as! Bool) == false) 1014 1015 // Check UInt*/Int* encode/decode 1016 data = EVM.encodeABI([ 1017 UInt8(33), 1018 UInt16(33), 1019 UInt32(33), 1020 UInt64(33), 1021 UInt128(33), 1022 UInt256(33), 1023 Int8(-33), 1024 Int16(-33), 1025 Int32(-33), 1026 Int64(-33), 1027 Int128(-33), 1028 Int256(-33) 1029 ]) 1030 values = EVM.decodeABI( 1031 types: [ 1032 Type<UInt8>(), 1033 Type<UInt16>(), 1034 Type<UInt32>(), 1035 Type<UInt64>(), 1036 Type<UInt128>(), 1037 Type<UInt256>(), 1038 Type<Int8>(), 1039 Type<Int16>(), 1040 Type<Int32>(), 1041 Type<Int64>(), 1042 Type<Int128>(), 1043 Type<Int256>() 1044 ], 1045 data: data 1046 ) 1047 assert((values[0] as! UInt8) == 33) 1048 assert((values[1] as! UInt16) == 33) 1049 assert((values[2] as! UInt32) == 33) 1050 assert((values[3] as! UInt64) == 33) 1051 assert((values[4] as! UInt128) == 33) 1052 assert((values[5] as! UInt256) == 33) 1053 assert((values[6] as! Int8) == -33) 1054 assert((values[7] as! Int16) == -33) 1055 assert((values[8] as! Int32) == -33) 1056 assert((values[9] as! Int64) == -33) 1057 assert((values[10] as! Int128) == -33) 1058 assert((values[11] as! Int256) == -33) 1059 1060 // Check variable-size array of leaf types encode/decode 1061 data = EVM.encodeABI([ 1062 ["one", "two"], 1063 [true, false], 1064 [5, 10] as [UInt8], 1065 [5, 10] as [UInt16], 1066 [5, 10] as [UInt32], 1067 [5, 10] as [UInt64], 1068 [5, 10] as [UInt128], 1069 [5, 10] as [UInt256], 1070 [-5, -10] as [Int8], 1071 [-5, -10] as [Int16], 1072 [-5, -10] as [Int32], 1073 [-5, -10] as [Int64], 1074 [-5, -10] as [Int128], 1075 [-5, -10] as [Int256], 1076 [address] as [EVM.EVMAddress] 1077 ]) 1078 values = EVM.decodeABI( 1079 types: [ 1080 Type<[String]>(), 1081 Type<[Bool]>(), 1082 Type<[UInt8]>(), 1083 Type<[UInt16]>(), 1084 Type<[UInt32]>(), 1085 Type<[UInt64]>(), 1086 Type<[UInt128]>(), 1087 Type<[UInt256]>(), 1088 Type<[Int8]>(), 1089 Type<[Int16]>(), 1090 Type<[Int32]>(), 1091 Type<[Int64]>(), 1092 Type<[Int128]>(), 1093 Type<[Int256]>(), 1094 Type<[EVM.EVMAddress]>() 1095 ], 1096 data: data 1097 ) 1098 assert((values[0] as! [String]) == ["one", "two"]) 1099 assert((values[1] as! [Bool]) == [true, false]) 1100 assert((values[2] as! [UInt8]) == [5, 10]) 1101 assert((values[3] as! [UInt16]) == [5, 10]) 1102 assert((values[4] as! [UInt32]) == [5, 10]) 1103 assert((values[5] as! [UInt64]) == [5, 10]) 1104 assert((values[6] as! [UInt128]) == [5, 10]) 1105 assert((values[7] as! [UInt256]) == [5, 10]) 1106 assert((values[8] as! [Int8]) == [-5, -10]) 1107 assert((values[9] as! [Int16]) == [-5, -10]) 1108 assert((values[10] as! [Int32]) == [-5, -10]) 1109 assert((values[11] as! [Int64]) == [-5, -10]) 1110 assert((values[12] as! [Int128]) == [-5, -10]) 1111 assert((values[13] as! [Int256]) == [-5, -10]) 1112 assert((values[14] as! [EVM.EVMAddress])[0].bytes == [address][0].bytes) 1113 1114 // Check constant-size array of leaf types encode/decode 1115 data = EVM.encodeABI([ 1116 ["one", "two"] as [String; 2], 1117 [true, false] as [Bool; 2], 1118 [5, 10] as [UInt8; 2], 1119 [5, 10] as [UInt16; 2], 1120 [5, 10] as [UInt32; 2], 1121 [5, 10] as [UInt64; 2], 1122 [5, 10] as [UInt128; 2], 1123 [5, 10] as [UInt256; 2], 1124 [-5, -10] as [Int8; 2], 1125 [-5, -10] as [Int16; 2], 1126 [-5, -10] as [Int32; 2], 1127 [-5, -10] as [Int64; 2], 1128 [-5, -10] as [Int128; 2], 1129 [-5, -10] as [Int256; 2], 1130 [address] as [EVM.EVMAddress; 1] 1131 ]) 1132 values = EVM.decodeABI( 1133 types: [ 1134 Type<[String; 2]>(), 1135 Type<[Bool; 2]>(), 1136 Type<[UInt8; 2]>(), 1137 Type<[UInt16; 2]>(), 1138 Type<[UInt32; 2]>(), 1139 Type<[UInt64; 2]>(), 1140 Type<[UInt128; 2]>(), 1141 Type<[UInt256; 2]>(), 1142 Type<[Int8; 2]>(), 1143 Type<[Int16; 2]>(), 1144 Type<[Int32; 2]>(), 1145 Type<[Int64; 2]>(), 1146 Type<[Int128; 2]>(), 1147 Type<[Int256; 2]>(), 1148 Type<[EVM.EVMAddress; 1]>() 1149 ], 1150 data: data 1151 ) 1152 assert((values[0] as! [String; 2]) == ["one", "two"]) 1153 assert((values[1] as! [Bool; 2]) == [true, false]) 1154 assert((values[2] as! [UInt8; 2]) == [5, 10]) 1155 assert((values[3] as! [UInt16; 2]) == [5, 10]) 1156 assert((values[4] as! [UInt32; 2]) == [5, 10]) 1157 assert((values[5] as! [UInt64; 2]) == [5, 10]) 1158 assert((values[6] as! [UInt128; 2]) == [5, 10]) 1159 assert((values[7] as! [UInt256; 2]) == [5, 10]) 1160 assert((values[8] as! [Int8; 2]) == [-5, -10]) 1161 assert((values[9] as! [Int16; 2]) == [-5, -10]) 1162 assert((values[10] as! [Int32; 2]) == [-5, -10]) 1163 assert((values[11] as! [Int64; 2]) == [-5, -10]) 1164 assert((values[12] as! [Int128; 2]) == [-5, -10]) 1165 assert((values[13] as! [Int256; 2]) == [-5, -10]) 1166 assert((values[14] as! [EVM.EVMAddress; 1])[0].bytes == [address][0].bytes) 1167 1168 // Check partial decoding of encoded data 1169 data = EVM.encodeABI(["Peter", UInt64(9999)]) 1170 values = EVM.decodeABI(types: [Type<String>()], data: data) 1171 assert(values.length == 1) 1172 assert((values[0] as! String) == "Peter") 1173 1174 // Check nested arrays of leaf values 1175 data = EVM.encodeABI([[["Foo", "Bar"], ["Baz", "Qux"]]]) 1176 values = EVM.decodeABI(types: [Type<[[String]]>()], data: data) 1177 assert(values.length == 1) 1178 assert((values[0] as! [[String]]) == [["Foo", "Bar"], ["Baz", "Qux"]]) 1179 1180 return true 1181 } 1182 `) 1183 1184 accountCodes := map[common.Location][]byte{} 1185 var events []cadence.Event 1186 1187 runtimeInterface := &TestRuntimeInterface{ 1188 Storage: NewTestLedger(nil, nil), 1189 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1190 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1191 }, 1192 OnResolveLocation: LocationResolver, 1193 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1194 accountCodes[location] = code 1195 return nil 1196 }, 1197 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1198 code = accountCodes[location] 1199 return code, nil 1200 }, 1201 OnEmitEvent: func(event cadence.Event) error { 1202 events = append(events, event) 1203 return nil 1204 }, 1205 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1206 return json.Decode(nil, b) 1207 }, 1208 } 1209 1210 nextTransactionLocation := NewTransactionLocationGenerator() 1211 nextScriptLocation := NewScriptLocationGenerator() 1212 1213 // Deploy contracts 1214 1215 deployContracts( 1216 t, 1217 rt, 1218 contractsAddress, 1219 runtimeInterface, 1220 transactionEnvironment, 1221 nextTransactionLocation, 1222 ) 1223 1224 // Run script 1225 1226 result, err := rt.ExecuteScript( 1227 runtime.Script{ 1228 Source: script, 1229 Arguments: [][]byte{}, 1230 }, 1231 runtime.Context{ 1232 Interface: runtimeInterface, 1233 Environment: scriptEnvironment, 1234 Location: nextScriptLocation(), 1235 }, 1236 ) 1237 require.NoError(t, err) 1238 1239 assert.Equal(t, 1240 cadence.Bool(true), 1241 result, 1242 ) 1243 } 1244 1245 func TestEVMEncodeDecodeABIErrors(t *testing.T) { 1246 1247 t.Parallel() 1248 1249 t.Run("encodeABI with unsupported Address type", func(t *testing.T) { 1250 1251 t.Parallel() 1252 1253 handler := &testContractHandler{} 1254 1255 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1256 1257 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1258 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1259 1260 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1261 1262 accountCodes := map[common.Location][]byte{} 1263 var events []cadence.Event 1264 1265 runtimeInterface := &TestRuntimeInterface{ 1266 Storage: NewTestLedger(nil, nil), 1267 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1268 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1269 }, 1270 OnResolveLocation: LocationResolver, 1271 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1272 accountCodes[location] = code 1273 return nil 1274 }, 1275 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1276 code = accountCodes[location] 1277 return code, nil 1278 }, 1279 OnEmitEvent: func(event cadence.Event) error { 1280 events = append(events, event) 1281 return nil 1282 }, 1283 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1284 return json.Decode(nil, b) 1285 }, 1286 } 1287 1288 nextTransactionLocation := NewTransactionLocationGenerator() 1289 nextScriptLocation := NewScriptLocationGenerator() 1290 1291 // Deploy contracts 1292 1293 deployContracts( 1294 t, 1295 rt, 1296 contractsAddress, 1297 runtimeInterface, 1298 transactionEnvironment, 1299 nextTransactionLocation, 1300 ) 1301 1302 // Run script 1303 1304 script := []byte(` 1305 import EVM from 0x1 1306 1307 access(all) 1308 fun main(): Bool { 1309 let address: Address = 0x045a1763c93006ca 1310 let data = EVM.encodeABI([address]) 1311 1312 return true 1313 } 1314 `) 1315 1316 _, err := rt.ExecuteScript( 1317 runtime.Script{ 1318 Source: script, 1319 Arguments: [][]byte{}, 1320 }, 1321 runtime.Context{ 1322 Interface: runtimeInterface, 1323 Environment: scriptEnvironment, 1324 Location: nextScriptLocation(), 1325 }, 1326 ) 1327 utils.RequireError(t, err) 1328 assert.ErrorContains( 1329 t, 1330 err, 1331 "failed to ABI encode value of type Address", 1332 ) 1333 }) 1334 1335 t.Run("encodeABI with unsupported fixed-point number type", func(t *testing.T) { 1336 1337 t.Parallel() 1338 1339 handler := &testContractHandler{} 1340 1341 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1342 1343 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1344 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1345 1346 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1347 1348 accountCodes := map[common.Location][]byte{} 1349 var events []cadence.Event 1350 1351 runtimeInterface := &TestRuntimeInterface{ 1352 Storage: NewTestLedger(nil, nil), 1353 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1354 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1355 }, 1356 OnResolveLocation: LocationResolver, 1357 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1358 accountCodes[location] = code 1359 return nil 1360 }, 1361 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1362 code = accountCodes[location] 1363 return code, nil 1364 }, 1365 OnEmitEvent: func(event cadence.Event) error { 1366 events = append(events, event) 1367 return nil 1368 }, 1369 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1370 return json.Decode(nil, b) 1371 }, 1372 } 1373 1374 nextTransactionLocation := NewTransactionLocationGenerator() 1375 nextScriptLocation := NewScriptLocationGenerator() 1376 1377 // Deploy contracts 1378 1379 deployContracts( 1380 t, 1381 rt, 1382 contractsAddress, 1383 runtimeInterface, 1384 transactionEnvironment, 1385 nextTransactionLocation, 1386 ) 1387 1388 // Run script 1389 1390 script := []byte(` 1391 import EVM from 0x1 1392 1393 access(all) 1394 fun main(): Bool { 1395 let data = EVM.encodeABI([0.2]) 1396 1397 return true 1398 } 1399 `) 1400 1401 _, err := rt.ExecuteScript( 1402 runtime.Script{ 1403 Source: script, 1404 Arguments: [][]byte{}, 1405 }, 1406 runtime.Context{ 1407 Interface: runtimeInterface, 1408 Environment: scriptEnvironment, 1409 Location: nextScriptLocation(), 1410 }, 1411 ) 1412 utils.RequireError(t, err) 1413 assert.ErrorContains( 1414 t, 1415 err, 1416 "failed to ABI encode value of type UFix64", 1417 ) 1418 }) 1419 1420 t.Run("encodeABI with unsupported dictionary type", func(t *testing.T) { 1421 1422 t.Parallel() 1423 1424 handler := &testContractHandler{} 1425 1426 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1427 1428 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1429 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1430 1431 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1432 1433 accountCodes := map[common.Location][]byte{} 1434 var events []cadence.Event 1435 1436 runtimeInterface := &TestRuntimeInterface{ 1437 Storage: NewTestLedger(nil, nil), 1438 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1439 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1440 }, 1441 OnResolveLocation: LocationResolver, 1442 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1443 accountCodes[location] = code 1444 return nil 1445 }, 1446 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1447 code = accountCodes[location] 1448 return code, nil 1449 }, 1450 OnEmitEvent: func(event cadence.Event) error { 1451 events = append(events, event) 1452 return nil 1453 }, 1454 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1455 return json.Decode(nil, b) 1456 }, 1457 } 1458 1459 nextTransactionLocation := NewTransactionLocationGenerator() 1460 nextScriptLocation := NewScriptLocationGenerator() 1461 1462 // Deploy contracts 1463 1464 deployContracts( 1465 t, 1466 rt, 1467 contractsAddress, 1468 runtimeInterface, 1469 transactionEnvironment, 1470 nextTransactionLocation, 1471 ) 1472 1473 // Run script 1474 1475 script := []byte(` 1476 import EVM from 0x1 1477 1478 access(all) 1479 fun main(): Bool { 1480 let dict: {Int: Bool} = {0: false, 1: true} 1481 let data = EVM.encodeABI([dict]) 1482 1483 return true 1484 } 1485 `) 1486 1487 _, err := rt.ExecuteScript( 1488 runtime.Script{ 1489 Source: script, 1490 Arguments: [][]byte{}, 1491 }, 1492 runtime.Context{ 1493 Interface: runtimeInterface, 1494 Environment: scriptEnvironment, 1495 Location: nextScriptLocation(), 1496 }, 1497 ) 1498 utils.RequireError(t, err) 1499 assert.ErrorContains( 1500 t, 1501 err, 1502 "failed to ABI encode value of type {Int: Bool}", 1503 ) 1504 }) 1505 1506 t.Run("encodeABI with unsupported array element type", func(t *testing.T) { 1507 1508 t.Parallel() 1509 1510 handler := &testContractHandler{} 1511 1512 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1513 1514 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1515 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1516 1517 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1518 1519 accountCodes := map[common.Location][]byte{} 1520 var events []cadence.Event 1521 1522 runtimeInterface := &TestRuntimeInterface{ 1523 Storage: NewTestLedger(nil, nil), 1524 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1525 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1526 }, 1527 OnResolveLocation: LocationResolver, 1528 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1529 accountCodes[location] = code 1530 return nil 1531 }, 1532 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1533 code = accountCodes[location] 1534 return code, nil 1535 }, 1536 OnEmitEvent: func(event cadence.Event) error { 1537 events = append(events, event) 1538 return nil 1539 }, 1540 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1541 return json.Decode(nil, b) 1542 }, 1543 } 1544 1545 nextTransactionLocation := NewTransactionLocationGenerator() 1546 nextScriptLocation := NewScriptLocationGenerator() 1547 1548 // Deploy contracts 1549 1550 deployContracts( 1551 t, 1552 rt, 1553 contractsAddress, 1554 runtimeInterface, 1555 transactionEnvironment, 1556 nextTransactionLocation, 1557 ) 1558 1559 // Run script 1560 1561 script := []byte(` 1562 import EVM from 0x1 1563 1564 access(all) 1565 fun main(): Bool { 1566 let chars: [Character] = ["a", "b", "c"] 1567 let data = EVM.encodeABI([chars]) 1568 1569 return true 1570 } 1571 `) 1572 1573 _, err := rt.ExecuteScript( 1574 runtime.Script{ 1575 Source: script, 1576 Arguments: [][]byte{}, 1577 }, 1578 runtime.Context{ 1579 Interface: runtimeInterface, 1580 Environment: scriptEnvironment, 1581 Location: nextScriptLocation(), 1582 }, 1583 ) 1584 utils.RequireError(t, err) 1585 assert.ErrorContains( 1586 t, 1587 err, 1588 "failed to ABI encode value of type Character", 1589 ) 1590 }) 1591 1592 t.Run("encodeABI with unsupported custom composite type", func(t *testing.T) { 1593 1594 t.Parallel() 1595 1596 handler := &testContractHandler{} 1597 1598 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1599 1600 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1601 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1602 1603 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1604 1605 accountCodes := map[common.Location][]byte{} 1606 var events []cadence.Event 1607 1608 runtimeInterface := &TestRuntimeInterface{ 1609 Storage: NewTestLedger(nil, nil), 1610 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1611 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1612 }, 1613 OnResolveLocation: LocationResolver, 1614 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1615 accountCodes[location] = code 1616 return nil 1617 }, 1618 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1619 code = accountCodes[location] 1620 return code, nil 1621 }, 1622 OnEmitEvent: func(event cadence.Event) error { 1623 events = append(events, event) 1624 return nil 1625 }, 1626 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1627 return json.Decode(nil, b) 1628 }, 1629 } 1630 1631 nextTransactionLocation := NewTransactionLocationGenerator() 1632 nextScriptLocation := NewScriptLocationGenerator() 1633 1634 // Deploy contracts 1635 1636 deployContracts( 1637 t, 1638 rt, 1639 contractsAddress, 1640 runtimeInterface, 1641 transactionEnvironment, 1642 nextTransactionLocation, 1643 ) 1644 1645 // Run script 1646 1647 script := []byte(` 1648 import EVM from 0x1 1649 1650 access(all) struct Token { 1651 access(all) let id: Int 1652 access(all) var balance: UInt 1653 1654 init(id: Int, balance: UInt) { 1655 self.id = id 1656 self.balance = balance 1657 } 1658 } 1659 1660 access(all) 1661 fun main(): Bool { 1662 let token = Token(id: 9, balance: 150) 1663 let data = EVM.encodeABI([token]) 1664 1665 return true 1666 } 1667 `) 1668 1669 _, err := rt.ExecuteScript( 1670 runtime.Script{ 1671 Source: script, 1672 Arguments: [][]byte{}, 1673 }, 1674 runtime.Context{ 1675 Interface: runtimeInterface, 1676 Environment: scriptEnvironment, 1677 Location: nextScriptLocation(), 1678 }, 1679 ) 1680 utils.RequireError(t, err) 1681 assert.ErrorContains( 1682 t, 1683 err, 1684 "failed to ABI encode value of type s.0100000000000000000000000000000000000000000000000000000000000000.Token", 1685 ) 1686 }) 1687 1688 t.Run("decodeABI with mismatched type", func(t *testing.T) { 1689 1690 t.Parallel() 1691 1692 handler := &testContractHandler{} 1693 1694 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1695 1696 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1697 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1698 1699 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1700 1701 accountCodes := map[common.Location][]byte{} 1702 var events []cadence.Event 1703 1704 runtimeInterface := &TestRuntimeInterface{ 1705 Storage: NewTestLedger(nil, nil), 1706 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1707 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1708 }, 1709 OnResolveLocation: LocationResolver, 1710 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1711 accountCodes[location] = code 1712 return nil 1713 }, 1714 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1715 code = accountCodes[location] 1716 return code, nil 1717 }, 1718 OnEmitEvent: func(event cadence.Event) error { 1719 events = append(events, event) 1720 return nil 1721 }, 1722 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1723 return json.Decode(nil, b) 1724 }, 1725 } 1726 1727 nextTransactionLocation := NewTransactionLocationGenerator() 1728 nextScriptLocation := NewScriptLocationGenerator() 1729 1730 // Deploy contracts 1731 1732 deployContracts( 1733 t, 1734 rt, 1735 contractsAddress, 1736 runtimeInterface, 1737 transactionEnvironment, 1738 nextTransactionLocation, 1739 ) 1740 1741 // Run script 1742 1743 script := []byte(` 1744 import EVM from 0x1 1745 1746 access(all) 1747 fun main(): Bool { 1748 let data = EVM.encodeABI(["Peter"]) 1749 let values = EVM.decodeABI(types: [Type<Bool>()], data: data) 1750 1751 return true 1752 } 1753 `) 1754 1755 _, err := rt.ExecuteScript( 1756 runtime.Script{ 1757 Source: script, 1758 Arguments: [][]byte{}, 1759 }, 1760 runtime.Context{ 1761 Interface: runtimeInterface, 1762 Environment: scriptEnvironment, 1763 Location: nextScriptLocation(), 1764 }, 1765 ) 1766 utils.RequireError(t, err) 1767 assert.ErrorContains( 1768 t, 1769 err, 1770 "failed to ABI decode data", 1771 ) 1772 }) 1773 1774 t.Run("decodeABI with surplus of types", func(t *testing.T) { 1775 1776 t.Parallel() 1777 1778 handler := &testContractHandler{} 1779 1780 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1781 1782 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1783 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1784 1785 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1786 1787 accountCodes := map[common.Location][]byte{} 1788 var events []cadence.Event 1789 1790 runtimeInterface := &TestRuntimeInterface{ 1791 Storage: NewTestLedger(nil, nil), 1792 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1793 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1794 }, 1795 OnResolveLocation: LocationResolver, 1796 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1797 accountCodes[location] = code 1798 return nil 1799 }, 1800 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1801 code = accountCodes[location] 1802 return code, nil 1803 }, 1804 OnEmitEvent: func(event cadence.Event) error { 1805 events = append(events, event) 1806 return nil 1807 }, 1808 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1809 return json.Decode(nil, b) 1810 }, 1811 } 1812 1813 nextTransactionLocation := NewTransactionLocationGenerator() 1814 nextScriptLocation := NewScriptLocationGenerator() 1815 1816 // Deploy contracts 1817 1818 deployContracts( 1819 t, 1820 rt, 1821 contractsAddress, 1822 runtimeInterface, 1823 transactionEnvironment, 1824 nextTransactionLocation, 1825 ) 1826 1827 // Run script 1828 1829 script := []byte(` 1830 import EVM from 0x1 1831 1832 access(all) 1833 fun main(): Bool { 1834 let data = EVM.encodeABI(["Peter"]) 1835 let values = EVM.decodeABI(types: [Type<String>(), Type<Bool>()], data: data) 1836 1837 return true 1838 } 1839 `) 1840 1841 _, err := rt.ExecuteScript( 1842 runtime.Script{ 1843 Source: script, 1844 Arguments: [][]byte{}, 1845 }, 1846 runtime.Context{ 1847 Interface: runtimeInterface, 1848 Environment: scriptEnvironment, 1849 Location: nextScriptLocation(), 1850 }, 1851 ) 1852 utils.RequireError(t, err) 1853 assert.ErrorContains( 1854 t, 1855 err, 1856 "failed to ABI decode data", 1857 ) 1858 }) 1859 1860 t.Run("decodeABI with unsupported fixed-point number type", func(t *testing.T) { 1861 1862 t.Parallel() 1863 1864 handler := &testContractHandler{} 1865 1866 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1867 1868 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1869 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1870 1871 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1872 1873 accountCodes := map[common.Location][]byte{} 1874 var events []cadence.Event 1875 1876 runtimeInterface := &TestRuntimeInterface{ 1877 Storage: NewTestLedger(nil, nil), 1878 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1879 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1880 }, 1881 OnResolveLocation: LocationResolver, 1882 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1883 accountCodes[location] = code 1884 return nil 1885 }, 1886 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1887 code = accountCodes[location] 1888 return code, nil 1889 }, 1890 OnEmitEvent: func(event cadence.Event) error { 1891 events = append(events, event) 1892 return nil 1893 }, 1894 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1895 return json.Decode(nil, b) 1896 }, 1897 } 1898 1899 nextTransactionLocation := NewTransactionLocationGenerator() 1900 nextScriptLocation := NewScriptLocationGenerator() 1901 1902 // Deploy contracts 1903 1904 deployContracts( 1905 t, 1906 rt, 1907 contractsAddress, 1908 runtimeInterface, 1909 transactionEnvironment, 1910 nextTransactionLocation, 1911 ) 1912 1913 // Run script 1914 1915 script := []byte(` 1916 import EVM from 0x1 1917 1918 access(all) 1919 fun main(): Bool { 1920 let data = EVM.encodeABI(["Peter"]) 1921 let values = EVM.decodeABI(types: [Type<UFix64>()], data: data) 1922 1923 return true 1924 } 1925 `) 1926 1927 _, err := rt.ExecuteScript( 1928 runtime.Script{ 1929 Source: script, 1930 Arguments: [][]byte{}, 1931 }, 1932 runtime.Context{ 1933 Interface: runtimeInterface, 1934 Environment: scriptEnvironment, 1935 Location: nextScriptLocation(), 1936 }, 1937 ) 1938 utils.RequireError(t, err) 1939 assert.ErrorContains( 1940 t, 1941 err, 1942 "failed to ABI decode data with type UFix64", 1943 ) 1944 }) 1945 1946 t.Run("decodeABI with unsupported dictionary type", func(t *testing.T) { 1947 1948 t.Parallel() 1949 1950 handler := &testContractHandler{} 1951 1952 contractsAddress := flow.BytesToAddress([]byte{0x1}) 1953 1954 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 1955 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 1956 1957 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 1958 1959 accountCodes := map[common.Location][]byte{} 1960 var events []cadence.Event 1961 1962 runtimeInterface := &TestRuntimeInterface{ 1963 Storage: NewTestLedger(nil, nil), 1964 OnGetSigningAccounts: func() ([]runtime.Address, error) { 1965 return []runtime.Address{runtime.Address(contractsAddress)}, nil 1966 }, 1967 OnResolveLocation: LocationResolver, 1968 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 1969 accountCodes[location] = code 1970 return nil 1971 }, 1972 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 1973 code = accountCodes[location] 1974 return code, nil 1975 }, 1976 OnEmitEvent: func(event cadence.Event) error { 1977 events = append(events, event) 1978 return nil 1979 }, 1980 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 1981 return json.Decode(nil, b) 1982 }, 1983 } 1984 1985 nextTransactionLocation := NewTransactionLocationGenerator() 1986 nextScriptLocation := NewScriptLocationGenerator() 1987 1988 // Deploy contracts 1989 1990 deployContracts( 1991 t, 1992 rt, 1993 contractsAddress, 1994 runtimeInterface, 1995 transactionEnvironment, 1996 nextTransactionLocation, 1997 ) 1998 1999 // Run script 2000 2001 script := []byte(` 2002 import EVM from 0x1 2003 2004 access(all) 2005 fun main(): Bool { 2006 let data = EVM.encodeABI(["Peter"]) 2007 let values = EVM.decodeABI(types: [Type<{Int: Bool}>()], data: data) 2008 2009 return true 2010 } 2011 `) 2012 2013 _, err := rt.ExecuteScript( 2014 runtime.Script{ 2015 Source: script, 2016 Arguments: [][]byte{}, 2017 }, 2018 runtime.Context{ 2019 Interface: runtimeInterface, 2020 Environment: scriptEnvironment, 2021 Location: nextScriptLocation(), 2022 }, 2023 ) 2024 utils.RequireError(t, err) 2025 assert.ErrorContains( 2026 t, 2027 err, 2028 "failed to ABI decode data with type {Int: Bool}", 2029 ) 2030 }) 2031 2032 t.Run("decodeABI with unsupported array element type", func(t *testing.T) { 2033 2034 t.Parallel() 2035 2036 handler := &testContractHandler{} 2037 2038 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2039 2040 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2041 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2042 2043 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2044 2045 accountCodes := map[common.Location][]byte{} 2046 var events []cadence.Event 2047 2048 runtimeInterface := &TestRuntimeInterface{ 2049 Storage: NewTestLedger(nil, nil), 2050 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2051 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2052 }, 2053 OnResolveLocation: LocationResolver, 2054 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2055 accountCodes[location] = code 2056 return nil 2057 }, 2058 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2059 code = accountCodes[location] 2060 return code, nil 2061 }, 2062 OnEmitEvent: func(event cadence.Event) error { 2063 events = append(events, event) 2064 return nil 2065 }, 2066 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2067 return json.Decode(nil, b) 2068 }, 2069 } 2070 2071 nextTransactionLocation := NewTransactionLocationGenerator() 2072 nextScriptLocation := NewScriptLocationGenerator() 2073 2074 // Deploy contracts 2075 2076 deployContracts( 2077 t, 2078 rt, 2079 contractsAddress, 2080 runtimeInterface, 2081 transactionEnvironment, 2082 nextTransactionLocation, 2083 ) 2084 2085 // Run script 2086 2087 script := []byte(` 2088 import EVM from 0x1 2089 2090 access(all) 2091 fun main(): Bool { 2092 let data = EVM.encodeABI(["Peter"]) 2093 let values = EVM.decodeABI(types: [Type<[Character]>()], data: data) 2094 2095 return true 2096 } 2097 `) 2098 2099 _, err := rt.ExecuteScript( 2100 runtime.Script{ 2101 Source: script, 2102 Arguments: [][]byte{}, 2103 }, 2104 runtime.Context{ 2105 Interface: runtimeInterface, 2106 Environment: scriptEnvironment, 2107 Location: nextScriptLocation(), 2108 }, 2109 ) 2110 utils.RequireError(t, err) 2111 assert.ErrorContains( 2112 t, 2113 err, 2114 "failed to ABI decode data with type [Character]", 2115 ) 2116 }) 2117 2118 t.Run("decodeABI with unsupported custom composite type", func(t *testing.T) { 2119 2120 t.Parallel() 2121 2122 handler := &testContractHandler{} 2123 2124 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2125 2126 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2127 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2128 2129 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2130 2131 accountCodes := map[common.Location][]byte{} 2132 var events []cadence.Event 2133 2134 runtimeInterface := &TestRuntimeInterface{ 2135 Storage: NewTestLedger(nil, nil), 2136 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2137 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2138 }, 2139 OnResolveLocation: LocationResolver, 2140 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2141 accountCodes[location] = code 2142 return nil 2143 }, 2144 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2145 code = accountCodes[location] 2146 return code, nil 2147 }, 2148 OnEmitEvent: func(event cadence.Event) error { 2149 events = append(events, event) 2150 return nil 2151 }, 2152 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2153 return json.Decode(nil, b) 2154 }, 2155 } 2156 2157 nextTransactionLocation := NewTransactionLocationGenerator() 2158 nextScriptLocation := NewScriptLocationGenerator() 2159 2160 // Deploy contracts 2161 2162 deployContracts( 2163 t, 2164 rt, 2165 contractsAddress, 2166 runtimeInterface, 2167 transactionEnvironment, 2168 nextTransactionLocation, 2169 ) 2170 2171 // Run script 2172 2173 script := []byte(` 2174 import EVM from 0x1 2175 2176 access(all) struct Token { 2177 access(all) let id: Int 2178 access(all) var balance: UInt 2179 2180 init(id: Int, balance: UInt) { 2181 self.id = id 2182 self.balance = balance 2183 } 2184 } 2185 2186 access(all) 2187 fun main(): Bool { 2188 let data = EVM.encodeABI(["Peter"]) 2189 let values = EVM.decodeABI(types: [Type<Token>()], data: data) 2190 2191 return true 2192 } 2193 `) 2194 2195 _, err := rt.ExecuteScript( 2196 runtime.Script{ 2197 Source: script, 2198 Arguments: [][]byte{}, 2199 }, 2200 runtime.Context{ 2201 Interface: runtimeInterface, 2202 Environment: scriptEnvironment, 2203 Location: nextScriptLocation(), 2204 }, 2205 ) 2206 utils.RequireError(t, err) 2207 assert.ErrorContains( 2208 t, 2209 err, 2210 "failed to ABI decode data with type s.0100000000000000000000000000000000000000000000000000000000000000.Token", 2211 ) 2212 }) 2213 } 2214 2215 func TestEVMEncodeABIWithSignature(t *testing.T) { 2216 2217 t.Parallel() 2218 2219 handler := &testContractHandler{} 2220 2221 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2222 2223 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2224 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2225 2226 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2227 2228 script := []byte(` 2229 import EVM from 0x1 2230 2231 access(all) 2232 fun main(): [UInt8] { 2233 // bytes for address 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71 2234 let address = EVM.EVMAddress( 2235 bytes: [ 2236 122, 88, 192, 190, 114, 190, 33, 139, 65, 198, 2237 8, 183, 254, 124, 91, 182, 48, 115, 108, 113 2238 ] 2239 ) 2240 2241 return EVM.encodeABIWithSignature( 2242 "withdraw(address,uint256)", 2243 [address, UInt256(250)] 2244 ) 2245 } 2246 `) 2247 2248 accountCodes := map[common.Location][]byte{} 2249 var events []cadence.Event 2250 2251 computation := uint(0) 2252 runtimeInterface := &TestRuntimeInterface{ 2253 Storage: NewTestLedger(nil, nil), 2254 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2255 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2256 }, 2257 OnResolveLocation: LocationResolver, 2258 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2259 accountCodes[location] = code 2260 return nil 2261 }, 2262 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2263 code = accountCodes[location] 2264 return code, nil 2265 }, 2266 OnEmitEvent: func(event cadence.Event) error { 2267 events = append(events, event) 2268 return nil 2269 }, 2270 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2271 return json.Decode(nil, b) 2272 }, 2273 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 2274 if compKind == environment.ComputationKindEVMEncodeABI { 2275 computation += intensity 2276 } 2277 return nil 2278 }, 2279 OnHash: func( 2280 data []byte, 2281 tag string, 2282 hashAlgorithm runtime.HashAlgorithm, 2283 ) ([]byte, error) { 2284 return crypto.Keccak256(data), nil 2285 }, 2286 } 2287 2288 nextTransactionLocation := NewTransactionLocationGenerator() 2289 nextScriptLocation := NewScriptLocationGenerator() 2290 2291 // Deploy contracts 2292 2293 deployContracts( 2294 t, 2295 rt, 2296 contractsAddress, 2297 runtimeInterface, 2298 transactionEnvironment, 2299 nextTransactionLocation, 2300 ) 2301 2302 // Run script 2303 2304 result, err := rt.ExecuteScript( 2305 runtime.Script{ 2306 Source: script, 2307 Arguments: [][]byte{}, 2308 }, 2309 runtime.Context{ 2310 Interface: runtimeInterface, 2311 Environment: scriptEnvironment, 2312 Location: nextScriptLocation(), 2313 }, 2314 ) 2315 require.NoError(t, err) 2316 2317 abiBytes := []byte{ 2318 0xf3, 0xfe, 0xf3, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2319 0x0, 0x0, 0x0, 0x7a, 0x58, 0xc0, 0xbe, 0x72, 0xbe, 0x21, 0x8b, 0x41, 2320 0xc6, 0x8, 0xb7, 0xfe, 0x7c, 0x5b, 0xb6, 0x30, 0x73, 0x6c, 0x71, 0x0, 2321 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2322 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2323 0x0, 0x0, 0xfa, 2324 } 2325 cdcBytes := make([]cadence.Value, 0) 2326 for _, bt := range abiBytes { 2327 cdcBytes = append(cdcBytes, cadence.UInt8(bt)) 2328 } 2329 encodedABI := cadence.NewArray( 2330 cdcBytes, 2331 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 2332 2333 assert.Equal(t, 2334 encodedABI, 2335 result, 2336 ) 2337 // The method ID is a byte array of length 4 2338 assert.Equal(t, computation+4, uint(len(cdcBytes))) 2339 } 2340 2341 func TestEVMDecodeABIWithSignature(t *testing.T) { 2342 2343 t.Parallel() 2344 2345 handler := &testContractHandler{} 2346 2347 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2348 2349 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2350 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2351 2352 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2353 2354 script := []byte(` 2355 import EVM from 0x1 2356 2357 access(all) 2358 fun main(data: [UInt8]): Bool { 2359 let values = EVM.decodeABIWithSignature( 2360 "withdraw(address,uint256)", 2361 types: [Type<EVM.EVMAddress>(), Type<UInt256>()], 2362 data: data 2363 ) 2364 2365 // bytes for address 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71 2366 let address = EVM.EVMAddress( 2367 bytes: [ 2368 122, 88, 192, 190, 114, 190, 33, 139, 65, 198, 2369 8, 183, 254, 124, 91, 182, 48, 115, 108, 113 2370 ] 2371 ) 2372 2373 assert(values.length == 2) 2374 assert((values[0] as! EVM.EVMAddress).bytes == address.bytes) 2375 assert((values[1] as! UInt256) == UInt256(250)) 2376 2377 return true 2378 } 2379 `) 2380 2381 accountCodes := map[common.Location][]byte{} 2382 var events []cadence.Event 2383 2384 computation := uint(0) 2385 runtimeInterface := &TestRuntimeInterface{ 2386 Storage: NewTestLedger(nil, nil), 2387 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2388 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2389 }, 2390 OnResolveLocation: LocationResolver, 2391 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2392 accountCodes[location] = code 2393 return nil 2394 }, 2395 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2396 code = accountCodes[location] 2397 return code, nil 2398 }, 2399 OnEmitEvent: func(event cadence.Event) error { 2400 events = append(events, event) 2401 return nil 2402 }, 2403 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2404 return json.Decode(nil, b) 2405 }, 2406 OnMeterComputation: func(compKind common.ComputationKind, intensity uint) error { 2407 if compKind == environment.ComputationKindEVMDecodeABI { 2408 computation += intensity 2409 } 2410 return nil 2411 }, 2412 OnHash: func( 2413 data []byte, 2414 tag string, 2415 hashAlgorithm runtime.HashAlgorithm, 2416 ) ([]byte, error) { 2417 return crypto.Keccak256(data), nil 2418 }, 2419 } 2420 2421 nextTransactionLocation := NewTransactionLocationGenerator() 2422 nextScriptLocation := NewScriptLocationGenerator() 2423 2424 // Deploy contracts 2425 2426 deployContracts( 2427 t, 2428 rt, 2429 contractsAddress, 2430 runtimeInterface, 2431 transactionEnvironment, 2432 nextTransactionLocation, 2433 ) 2434 2435 // Run script 2436 abiBytes := []byte{ 2437 0xf3, 0xfe, 0xf3, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2438 0x0, 0x0, 0x0, 0x7a, 0x58, 0xc0, 0xbe, 0x72, 0xbe, 0x21, 0x8b, 0x41, 2439 0xc6, 0x8, 0xb7, 0xfe, 0x7c, 0x5b, 0xb6, 0x30, 0x73, 0x6c, 0x71, 0x0, 2440 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2441 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2442 0x0, 0x0, 0xfa, 2443 } 2444 cdcBytes := make([]cadence.Value, 0) 2445 for _, bt := range abiBytes { 2446 cdcBytes = append(cdcBytes, cadence.UInt8(bt)) 2447 } 2448 encodedABI := cadence.NewArray( 2449 cdcBytes, 2450 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 2451 2452 result, err := rt.ExecuteScript( 2453 runtime.Script{ 2454 Source: script, 2455 Arguments: EncodeArgs([]cadence.Value{ 2456 encodedABI, 2457 }), 2458 }, 2459 runtime.Context{ 2460 Interface: runtimeInterface, 2461 Environment: scriptEnvironment, 2462 Location: nextScriptLocation(), 2463 }, 2464 ) 2465 require.NoError(t, err) 2466 2467 assert.Equal(t, cadence.NewBool(true), result) 2468 // The method ID is a byte array of length 4 2469 assert.Equal(t, computation+4, uint(len(cdcBytes))) 2470 } 2471 2472 func TestEVMDecodeABIWithSignatureMismatch(t *testing.T) { 2473 2474 t.Parallel() 2475 2476 handler := &testContractHandler{} 2477 2478 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2479 2480 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2481 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2482 2483 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2484 2485 script := []byte(` 2486 import EVM from 0x1 2487 2488 access(all) 2489 fun main(data: [UInt8]): Bool { 2490 // The data was encoded for the function "withdraw(address,uint256)", 2491 // but we pass a different function signature 2492 let values = EVM.decodeABIWithSignature( 2493 "deposit(uint256, address)", 2494 types: [Type<UInt256>(), Type<EVM.EVMAddress>()], 2495 data: data 2496 ) 2497 2498 return true 2499 } 2500 `) 2501 2502 accountCodes := map[common.Location][]byte{} 2503 var events []cadence.Event 2504 2505 runtimeInterface := &TestRuntimeInterface{ 2506 Storage: NewTestLedger(nil, nil), 2507 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2508 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2509 }, 2510 OnResolveLocation: LocationResolver, 2511 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2512 accountCodes[location] = code 2513 return nil 2514 }, 2515 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2516 code = accountCodes[location] 2517 return code, nil 2518 }, 2519 OnEmitEvent: func(event cadence.Event) error { 2520 events = append(events, event) 2521 return nil 2522 }, 2523 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2524 return json.Decode(nil, b) 2525 }, 2526 OnHash: func( 2527 data []byte, 2528 tag string, 2529 hashAlgorithm runtime.HashAlgorithm, 2530 ) ([]byte, error) { 2531 return crypto.Keccak256(data), nil 2532 }, 2533 } 2534 2535 nextTransactionLocation := NewTransactionLocationGenerator() 2536 nextScriptLocation := NewScriptLocationGenerator() 2537 2538 // Deploy contracts 2539 2540 deployContracts( 2541 t, 2542 rt, 2543 contractsAddress, 2544 runtimeInterface, 2545 transactionEnvironment, 2546 nextTransactionLocation, 2547 ) 2548 2549 // Run script 2550 abiBytes := []byte{ 2551 0xf3, 0xfe, 0xf3, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2552 0x0, 0x0, 0x0, 0x7a, 0x58, 0xc0, 0xbe, 0x72, 0xbe, 0x21, 0x8b, 0x41, 2553 0xc6, 0x8, 0xb7, 0xfe, 0x7c, 0x5b, 0xb6, 0x30, 0x73, 0x6c, 0x71, 0x0, 2554 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2555 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2556 0x0, 0x0, 0xfa, 2557 } 2558 cdcBytes := make([]cadence.Value, 0) 2559 for _, bt := range abiBytes { 2560 cdcBytes = append(cdcBytes, cadence.UInt8(bt)) 2561 } 2562 encodedABI := cadence.NewArray( 2563 cdcBytes, 2564 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 2565 2566 _, err := rt.ExecuteScript( 2567 runtime.Script{ 2568 Source: script, 2569 Arguments: EncodeArgs([]cadence.Value{ 2570 encodedABI, 2571 }), 2572 }, 2573 runtime.Context{ 2574 Interface: runtimeInterface, 2575 Environment: scriptEnvironment, 2576 Location: nextScriptLocation(), 2577 }, 2578 ) 2579 require.Error(t, err) 2580 assert.ErrorContains(t, err, "panic: signature mismatch") 2581 } 2582 2583 func TestEVMAddressConstructionAndReturn(t *testing.T) { 2584 2585 t.Parallel() 2586 2587 handler := &testContractHandler{} 2588 2589 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2590 2591 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2592 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2593 2594 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2595 2596 script := []byte(` 2597 import EVM from 0x1 2598 2599 access(all) 2600 fun main(_ bytes: [UInt8; 20]): EVM.EVMAddress { 2601 return EVM.EVMAddress(bytes: bytes) 2602 } 2603 `) 2604 2605 accountCodes := map[common.Location][]byte{} 2606 var events []cadence.Event 2607 2608 runtimeInterface := &TestRuntimeInterface{ 2609 Storage: NewTestLedger(nil, nil), 2610 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2611 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2612 }, 2613 OnResolveLocation: LocationResolver, 2614 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2615 accountCodes[location] = code 2616 return nil 2617 }, 2618 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2619 code = accountCodes[location] 2620 return code, nil 2621 }, 2622 OnEmitEvent: func(event cadence.Event) error { 2623 events = append(events, event) 2624 return nil 2625 }, 2626 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2627 return json.Decode(nil, b) 2628 }, 2629 } 2630 2631 addressBytesArray := cadence.NewArray([]cadence.Value{ 2632 cadence.UInt8(1), cadence.UInt8(1), 2633 cadence.UInt8(2), cadence.UInt8(2), 2634 cadence.UInt8(3), cadence.UInt8(3), 2635 cadence.UInt8(4), cadence.UInt8(4), 2636 cadence.UInt8(5), cadence.UInt8(5), 2637 cadence.UInt8(6), cadence.UInt8(6), 2638 cadence.UInt8(7), cadence.UInt8(7), 2639 cadence.UInt8(8), cadence.UInt8(8), 2640 cadence.UInt8(9), cadence.UInt8(9), 2641 cadence.UInt8(10), cadence.UInt8(10), 2642 }).WithType(stdlib.EVMAddressBytesCadenceType) 2643 2644 nextTransactionLocation := NewTransactionLocationGenerator() 2645 nextScriptLocation := NewScriptLocationGenerator() 2646 2647 // Deploy contracts 2648 2649 deployContracts( 2650 t, 2651 rt, 2652 contractsAddress, 2653 runtimeInterface, 2654 transactionEnvironment, 2655 nextTransactionLocation, 2656 ) 2657 2658 // Run script 2659 2660 result, err := rt.ExecuteScript( 2661 runtime.Script{ 2662 Source: script, 2663 Arguments: EncodeArgs([]cadence.Value{ 2664 addressBytesArray, 2665 }), 2666 }, 2667 runtime.Context{ 2668 Interface: runtimeInterface, 2669 Environment: scriptEnvironment, 2670 Location: nextScriptLocation(), 2671 }, 2672 ) 2673 require.NoError(t, err) 2674 2675 evmAddressCadenceType := stdlib.NewEVMAddressCadenceType(common.Address(contractsAddress)) 2676 2677 assert.Equal(t, 2678 cadence.NewStruct([]cadence.Value{ 2679 addressBytesArray, 2680 }).WithType(evmAddressCadenceType), 2681 result, 2682 ) 2683 } 2684 2685 func TestEVMAddressSerializationAndDeserialization(t *testing.T) { 2686 2687 t.Parallel() 2688 2689 handler := &testContractHandler{} 2690 2691 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2692 2693 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2694 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2695 2696 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2697 2698 addressFromBytesScript := []byte(` 2699 import EVM from 0x1 2700 2701 access(all) 2702 fun main(_ bytes: [UInt8; 20]): EVM.EVMAddress { 2703 return EVM.EVMAddress(bytes: bytes) 2704 } 2705 `) 2706 2707 accountCodes := map[common.Location][]byte{} 2708 var events []cadence.Event 2709 2710 runtimeInterface := &TestRuntimeInterface{ 2711 Storage: NewTestLedger(nil, nil), 2712 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2713 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2714 }, 2715 OnResolveLocation: LocationResolver, 2716 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2717 accountCodes[location] = code 2718 return nil 2719 }, 2720 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2721 code = accountCodes[location] 2722 return code, nil 2723 }, 2724 OnEmitEvent: func(event cadence.Event) error { 2725 events = append(events, event) 2726 return nil 2727 }, 2728 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2729 return json.Decode(nil, b) 2730 }, 2731 } 2732 2733 sourceBytes := []byte{ 2734 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 2735 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 2736 } 2737 2738 // construct the address as a cadence value from sourceBytes 2739 addressBytesArray := cadence.NewArray([]cadence.Value{ 2740 cadence.UInt8(sourceBytes[0]), cadence.UInt8(sourceBytes[1]), 2741 cadence.UInt8(sourceBytes[2]), cadence.UInt8(sourceBytes[3]), 2742 cadence.UInt8(sourceBytes[4]), cadence.UInt8(sourceBytes[5]), 2743 cadence.UInt8(sourceBytes[6]), cadence.UInt8(sourceBytes[7]), 2744 cadence.UInt8(sourceBytes[8]), cadence.UInt8(sourceBytes[9]), 2745 cadence.UInt8(sourceBytes[10]), cadence.UInt8(sourceBytes[11]), 2746 cadence.UInt8(sourceBytes[12]), cadence.UInt8(sourceBytes[13]), 2747 cadence.UInt8(sourceBytes[14]), cadence.UInt8(sourceBytes[15]), 2748 cadence.UInt8(sourceBytes[16]), cadence.UInt8(sourceBytes[17]), 2749 cadence.UInt8(sourceBytes[18]), cadence.UInt8(sourceBytes[19]), 2750 }).WithType(stdlib.EVMAddressBytesCadenceType) 2751 2752 nextTransactionLocation := NewTransactionLocationGenerator() 2753 nextScriptLocation := NewScriptLocationGenerator() 2754 2755 // Deploy contracts 2756 2757 deployContracts( 2758 t, 2759 rt, 2760 contractsAddress, 2761 runtimeInterface, 2762 transactionEnvironment, 2763 nextTransactionLocation, 2764 ) 2765 2766 // Run script 2767 2768 constructAddrResult, err := rt.ExecuteScript( 2769 runtime.Script{ 2770 Source: addressFromBytesScript, 2771 Arguments: EncodeArgs([]cadence.Value{ 2772 addressBytesArray, 2773 }), 2774 }, 2775 runtime.Context{ 2776 Interface: runtimeInterface, 2777 Environment: scriptEnvironment, 2778 Location: nextScriptLocation(), 2779 }, 2780 ) 2781 require.NoError(t, err) 2782 2783 evmAddressCadenceType := stdlib.NewEVMAddressCadenceType(common.Address(contractsAddress)) 2784 evmAddress := cadence.NewStruct([]cadence.Value{ 2785 addressBytesArray, 2786 }).WithType(evmAddressCadenceType) 2787 2788 assert.Equal(t, 2789 evmAddress, 2790 constructAddrResult, 2791 ) 2792 2793 // Attempt to serialize and deserialize the address 2794 2795 addressSerializationScript := []byte(` 2796 import EVM from 0x1 2797 2798 access(all) 2799 fun main(address: EVM.EVMAddress): String { 2800 return address.toString() 2801 } 2802 `) 2803 2804 serializeAddrResult, err := rt.ExecuteScript( 2805 runtime.Script{ 2806 Source: addressSerializationScript, 2807 Arguments: EncodeArgs([]cadence.Value{ 2808 evmAddress, 2809 }), 2810 }, 2811 runtime.Context{ 2812 Interface: runtimeInterface, 2813 Environment: scriptEnvironment, 2814 Location: nextScriptLocation(), 2815 }, 2816 ) 2817 2818 require.NoError(t, err) 2819 2820 // Encode the sourceBytes array as a hex string as the expected value to compare the result against 2821 2822 expectedHex, _ := cadence.NewString(hex.EncodeToString(sourceBytes)) 2823 2824 assert.Equal(t, 2825 expectedHex, 2826 serializeAddrResult, 2827 ) 2828 2829 // Attempt to deserialize the address 2830 2831 addressDeserializationScript := []byte(` 2832 import EVM from 0x1 2833 2834 access(all) 2835 fun main(hexString: String): EVM.EVMAddress { 2836 return EVM.addressFromString(hexString) 2837 } 2838 `) 2839 2840 deserializeAddrResult, err := rt.ExecuteScript( 2841 runtime.Script{ 2842 Source: addressDeserializationScript, 2843 Arguments: EncodeArgs([]cadence.Value{ 2844 serializeAddrResult, 2845 }), 2846 }, 2847 runtime.Context{ 2848 Interface: runtimeInterface, 2849 Environment: scriptEnvironment, 2850 Location: nextScriptLocation(), 2851 }, 2852 ) 2853 2854 require.NoError(t, err) 2855 2856 assert.Equal(t, 2857 evmAddress, 2858 deserializeAddrResult, 2859 ) 2860 } 2861 2862 func TestBalanceConstructionAndReturn(t *testing.T) { 2863 2864 t.Parallel() 2865 2866 handler := &testContractHandler{} 2867 2868 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2869 2870 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2871 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2872 2873 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 2874 2875 script := []byte(` 2876 import EVM from 0x1 2877 2878 access(all) 2879 fun main(_ attoflow: UInt): EVM.Balance { 2880 return EVM.Balance(attoflow: attoflow) 2881 } 2882 `) 2883 2884 accountCodes := map[common.Location][]byte{} 2885 var events []cadence.Event 2886 2887 runtimeInterface := &TestRuntimeInterface{ 2888 Storage: NewTestLedger(nil, nil), 2889 OnGetSigningAccounts: func() ([]runtime.Address, error) { 2890 return []runtime.Address{runtime.Address(contractsAddress)}, nil 2891 }, 2892 OnResolveLocation: LocationResolver, 2893 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 2894 accountCodes[location] = code 2895 return nil 2896 }, 2897 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 2898 code = accountCodes[location] 2899 return code, nil 2900 }, 2901 OnEmitEvent: func(event cadence.Event) error { 2902 events = append(events, event) 2903 return nil 2904 }, 2905 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 2906 return json.Decode(nil, b) 2907 }, 2908 } 2909 2910 nextTransactionLocation := NewTransactionLocationGenerator() 2911 nextScriptLocation := NewScriptLocationGenerator() 2912 2913 // Deploy contracts 2914 2915 deployContracts( 2916 t, 2917 rt, 2918 contractsAddress, 2919 runtimeInterface, 2920 transactionEnvironment, 2921 nextTransactionLocation, 2922 ) 2923 2924 // Run script 2925 2926 flowValue := cadence.NewUInt(1230000000000000000) 2927 2928 result, err := rt.ExecuteScript( 2929 runtime.Script{ 2930 Source: script, 2931 Arguments: EncodeArgs([]cadence.Value{ 2932 flowValue, 2933 }), 2934 }, 2935 runtime.Context{ 2936 Interface: runtimeInterface, 2937 Environment: scriptEnvironment, 2938 Location: nextScriptLocation(), 2939 }, 2940 ) 2941 require.NoError(t, err) 2942 2943 evmBalanceCadenceType := stdlib.NewBalanceCadenceType(common.Address(contractsAddress)) 2944 2945 assert.Equal(t, 2946 cadence.NewStruct([]cadence.Value{ 2947 flowValue, 2948 }).WithType(evmBalanceCadenceType), 2949 result, 2950 ) 2951 } 2952 2953 func TestEVMRun(t *testing.T) { 2954 2955 t.Parallel() 2956 2957 evmTx := cadence.NewArray([]cadence.Value{ 2958 cadence.UInt8(1), 2959 cadence.UInt8(2), 2960 cadence.UInt8(3), 2961 }).WithType(stdlib.EVMTransactionBytesCadenceType) 2962 2963 coinbase := cadence.NewArray([]cadence.Value{ 2964 cadence.UInt8(1), cadence.UInt8(1), 2965 cadence.UInt8(2), cadence.UInt8(2), 2966 cadence.UInt8(3), cadence.UInt8(3), 2967 cadence.UInt8(4), cadence.UInt8(4), 2968 cadence.UInt8(5), cadence.UInt8(5), 2969 cadence.UInt8(6), cadence.UInt8(6), 2970 cadence.UInt8(7), cadence.UInt8(7), 2971 cadence.UInt8(8), cadence.UInt8(8), 2972 cadence.UInt8(9), cadence.UInt8(9), 2973 cadence.UInt8(10), cadence.UInt8(10), 2974 }).WithType(stdlib.EVMAddressBytesCadenceType) 2975 2976 runCalled := false 2977 2978 contractsAddress := flow.BytesToAddress([]byte{0x1}) 2979 handler := &testContractHandler{ 2980 evmContractAddress: common.Address(contractsAddress), 2981 run: func(tx []byte, coinbase types.Address) *types.ResultSummary { 2982 runCalled = true 2983 2984 assert.Equal(t, []byte{1, 2, 3}, tx) 2985 assert.Equal(t, 2986 types.Address{ 2987 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 2988 }, 2989 coinbase, 2990 ) 2991 return &types.ResultSummary{ 2992 Status: types.StatusSuccessful, 2993 } 2994 }, 2995 } 2996 2997 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 2998 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 2999 3000 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3001 3002 script := []byte(` 3003 import EVM from 0x1 3004 3005 access(all) 3006 fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): UInt8 { 3007 let coinbase = EVM.EVMAddress(bytes: coinbaseBytes) 3008 let res = EVM.run(tx: tx, coinbase: coinbase) 3009 let st = res.status 3010 return st.rawValue 3011 } 3012 `) 3013 3014 accountCodes := map[common.Location][]byte{} 3015 var events []cadence.Event 3016 3017 runtimeInterface := &TestRuntimeInterface{ 3018 Storage: NewTestLedger(nil, nil), 3019 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3020 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3021 }, 3022 OnResolveLocation: LocationResolver, 3023 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3024 accountCodes[location] = code 3025 return nil 3026 }, 3027 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3028 code = accountCodes[location] 3029 return code, nil 3030 }, 3031 OnEmitEvent: func(event cadence.Event) error { 3032 events = append(events, event) 3033 return nil 3034 }, 3035 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3036 return json.Decode(nil, b) 3037 }, 3038 } 3039 3040 nextTransactionLocation := NewTransactionLocationGenerator() 3041 nextScriptLocation := NewScriptLocationGenerator() 3042 3043 // Deploy contracts 3044 3045 deployContracts( 3046 t, 3047 rt, 3048 contractsAddress, 3049 runtimeInterface, 3050 transactionEnvironment, 3051 nextTransactionLocation, 3052 ) 3053 3054 // Run script 3055 3056 val, err := rt.ExecuteScript( 3057 runtime.Script{ 3058 Source: script, 3059 Arguments: EncodeArgs([]cadence.Value{evmTx, coinbase}), 3060 }, 3061 runtime.Context{ 3062 Interface: runtimeInterface, 3063 Environment: scriptEnvironment, 3064 Location: nextScriptLocation(), 3065 }, 3066 ) 3067 require.NoError(t, err) 3068 3069 assert.Equal(t, types.StatusSuccessful, types.Status(val.(cadence.UInt8))) 3070 assert.True(t, runCalled) 3071 3072 // test must run 3073 script = []byte(` 3074 import EVM from 0x1 3075 3076 access(all) 3077 fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): UInt8 { 3078 let coinbase = EVM.EVMAddress(bytes: coinbaseBytes) 3079 let res = EVM.mustRun(tx: tx, coinbase: coinbase) 3080 let st = res.status 3081 return st.rawValue 3082 } 3083 `) 3084 val, err = rt.ExecuteScript( 3085 runtime.Script{ 3086 Source: script, 3087 Arguments: EncodeArgs([]cadence.Value{evmTx, coinbase}), 3088 }, 3089 runtime.Context{ 3090 Interface: runtimeInterface, 3091 Environment: scriptEnvironment, 3092 Location: nextScriptLocation(), 3093 }, 3094 ) 3095 require.NoError(t, err) 3096 3097 assert.Equal(t, types.StatusSuccessful, types.Status(val.(cadence.UInt8))) 3098 assert.True(t, runCalled) 3099 } 3100 3101 func TestEVMDryRun(t *testing.T) { 3102 3103 t.Parallel() 3104 3105 dryRunCalled := false 3106 evmTx := cadence.NewArray([]cadence.Value{ 3107 cadence.UInt8(1), 3108 cadence.UInt8(2), 3109 cadence.UInt8(3), 3110 }).WithType(stdlib.EVMTransactionBytesCadenceType) 3111 3112 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3113 handler := &testContractHandler{ 3114 evmContractAddress: common.Address(contractsAddress), 3115 dryRun: func(tx []byte, from types.Address) *types.ResultSummary { 3116 dryRunCalled = true 3117 assert.Equal(t, types.Address{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, from) 3118 assert.Equal(t, tx, []byte{1, 2, 3}) 3119 3120 return &types.ResultSummary{ 3121 Status: types.StatusSuccessful, 3122 } 3123 }, 3124 } 3125 3126 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3127 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3128 3129 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3130 3131 accountCodes := map[common.Location][]byte{} 3132 var events []cadence.Event 3133 3134 runtimeInterface := &TestRuntimeInterface{ 3135 Storage: NewTestLedger(nil, nil), 3136 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3137 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3138 }, 3139 OnResolveLocation: LocationResolver, 3140 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3141 accountCodes[location] = code 3142 return nil 3143 }, 3144 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3145 code = accountCodes[location] 3146 return code, nil 3147 }, 3148 OnEmitEvent: func(event cadence.Event) error { 3149 events = append(events, event) 3150 return nil 3151 }, 3152 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3153 return json.Decode(nil, b) 3154 }, 3155 } 3156 3157 nextTransactionLocation := NewTransactionLocationGenerator() 3158 nextScriptLocation := NewScriptLocationGenerator() 3159 3160 // Deploy contracts 3161 3162 deployContracts( 3163 t, 3164 rt, 3165 contractsAddress, 3166 runtimeInterface, 3167 transactionEnvironment, 3168 nextTransactionLocation, 3169 ) 3170 3171 // Run script 3172 3173 script := []byte(` 3174 import EVM from 0x1 3175 3176 access(all) 3177 fun main(tx: [UInt8]): EVM.Result { 3178 return EVM.dryRun( 3179 tx: tx, 3180 from: EVM.EVMAddress(bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), // random address 3181 ) 3182 } 3183 `) 3184 3185 val, err := rt.ExecuteScript( 3186 runtime.Script{ 3187 Source: script, 3188 Arguments: EncodeArgs([]cadence.Value{evmTx}), 3189 }, 3190 runtime.Context{ 3191 Interface: runtimeInterface, 3192 Environment: scriptEnvironment, 3193 Location: nextScriptLocation(), 3194 }, 3195 ) 3196 require.NoError(t, err) 3197 res, err := stdlib.ResultSummaryFromEVMResultValue(val) 3198 require.NoError(t, err) 3199 assert.Equal(t, types.StatusSuccessful, res.Status) 3200 assert.True(t, dryRunCalled) 3201 } 3202 3203 func TestEVMBatchRun(t *testing.T) { 3204 3205 t.Parallel() 3206 3207 evmTxs := cadence.NewArray([]cadence.Value{ 3208 cadence.NewArray([]cadence.Value{cadence.UInt8(1), cadence.UInt8(2), cadence.UInt8(3)}), 3209 cadence.NewArray([]cadence.Value{cadence.UInt8(4), cadence.UInt8(5), cadence.UInt8(6)}), 3210 cadence.NewArray([]cadence.Value{cadence.UInt8(7), cadence.UInt8(8), cadence.UInt8(9)}), 3211 }).WithType(cadence.NewVariableSizedArrayType(cadence.NewVariableSizedArrayType(cadence.UInt8Type))) 3212 3213 coinbase := cadence.NewArray([]cadence.Value{ 3214 cadence.UInt8(1), cadence.UInt8(1), 3215 cadence.UInt8(2), cadence.UInt8(2), 3216 cadence.UInt8(3), cadence.UInt8(3), 3217 cadence.UInt8(4), cadence.UInt8(4), 3218 cadence.UInt8(5), cadence.UInt8(5), 3219 cadence.UInt8(6), cadence.UInt8(6), 3220 cadence.UInt8(7), cadence.UInt8(7), 3221 cadence.UInt8(8), cadence.UInt8(8), 3222 cadence.UInt8(9), cadence.UInt8(9), 3223 cadence.UInt8(10), cadence.UInt8(10), 3224 }).WithType(stdlib.EVMAddressBytesCadenceType) 3225 3226 runCalled := false 3227 3228 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3229 handler := &testContractHandler{ 3230 evmContractAddress: common.Address(contractsAddress), 3231 batchRun: func(txs [][]byte, coinbase types.Address) []*types.ResultSummary { 3232 runCalled = true 3233 3234 assert.EqualValues(t, [][]byte{ 3235 {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, 3236 }, txs) 3237 assert.Equal(t, 3238 types.Address{ 3239 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 3240 }, 3241 coinbase, 3242 ) 3243 3244 results := make([]*types.ResultSummary, 3) 3245 for i := range results { 3246 results[i] = &types.ResultSummary{ 3247 Status: types.StatusSuccessful, 3248 } 3249 } 3250 3251 return results 3252 }, 3253 } 3254 3255 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3256 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3257 3258 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3259 3260 script := []byte(` 3261 import EVM from 0x1 3262 3263 access(all) 3264 fun main(txs: [[UInt8]], coinbaseBytes: [UInt8; 20]): [EVM.Result] { 3265 let coinbase = EVM.EVMAddress(bytes: coinbaseBytes) 3266 return EVM.batchRun(txs: txs, coinbase: coinbase) 3267 } 3268 `) 3269 3270 accountCodes := map[common.Location][]byte{} 3271 var events []cadence.Event 3272 3273 runtimeInterface := &TestRuntimeInterface{ 3274 Storage: NewTestLedger(nil, nil), 3275 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3276 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3277 }, 3278 OnResolveLocation: LocationResolver, 3279 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3280 accountCodes[location] = code 3281 return nil 3282 }, 3283 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3284 code = accountCodes[location] 3285 return code, nil 3286 }, 3287 OnEmitEvent: func(event cadence.Event) error { 3288 events = append(events, event) 3289 return nil 3290 }, 3291 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3292 return json.Decode(nil, b) 3293 }, 3294 } 3295 3296 nextTransactionLocation := NewTransactionLocationGenerator() 3297 nextScriptLocation := NewScriptLocationGenerator() 3298 3299 // Deploy contracts 3300 3301 deployContracts( 3302 t, 3303 rt, 3304 contractsAddress, 3305 runtimeInterface, 3306 transactionEnvironment, 3307 nextTransactionLocation, 3308 ) 3309 3310 // Run script 3311 3312 val, err := rt.ExecuteScript( 3313 runtime.Script{ 3314 Source: script, 3315 Arguments: EncodeArgs([]cadence.Value{evmTxs, coinbase}), 3316 }, 3317 runtime.Context{ 3318 Interface: runtimeInterface, 3319 Environment: scriptEnvironment, 3320 Location: nextScriptLocation(), 3321 }, 3322 ) 3323 require.NoError(t, err) 3324 3325 resultsCadence, ok := val.(cadence.Array) 3326 require.True(t, ok) 3327 3328 for _, v := range resultsCadence.Values { 3329 res, err := stdlib.ResultSummaryFromEVMResultValue(v) 3330 require.NoError(t, err) 3331 assert.Equal(t, types.StatusSuccessful, res.Status) 3332 } 3333 assert.True(t, runCalled) 3334 } 3335 3336 func TestEVMCreateCadenceOwnedAccount(t *testing.T) { 3337 3338 t.Parallel() 3339 3340 uuidCounter := uint64(0) 3341 handler := &testContractHandler{ 3342 deployCOA: func(uuid uint64) types.Address { 3343 require.Equal(t, uuidCounter, uuid) 3344 return types.Address{uint8(uuidCounter)} 3345 }, 3346 } 3347 3348 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3349 3350 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3351 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3352 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3353 3354 script := []byte(` 3355 import EVM from 0x1 3356 3357 access(all) 3358 fun main(): [UInt8; 20] { 3359 let cadenceOwnedAccount1 <- EVM.createCadenceOwnedAccount() 3360 destroy cadenceOwnedAccount1 3361 3362 let cadenceOwnedAccount2 <- EVM.createCadenceOwnedAccount() 3363 let bytes = cadenceOwnedAccount2.address().bytes 3364 destroy cadenceOwnedAccount2 3365 3366 return bytes 3367 } 3368 `) 3369 3370 accountCodes := map[common.Location][]byte{} 3371 var events []cadence.Event 3372 3373 runtimeInterface := &TestRuntimeInterface{ 3374 Storage: NewTestLedger(nil, nil), 3375 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3376 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3377 }, 3378 OnResolveLocation: LocationResolver, 3379 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3380 accountCodes[location] = code 3381 return nil 3382 }, 3383 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3384 code = accountCodes[location] 3385 return code, nil 3386 }, 3387 OnEmitEvent: func(event cadence.Event) error { 3388 events = append(events, event) 3389 return nil 3390 }, 3391 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3392 return json.Decode(nil, b) 3393 }, 3394 OnGenerateUUID: func() (uint64, error) { 3395 uuidCounter++ 3396 return uuidCounter, nil 3397 }, 3398 } 3399 3400 nextTransactionLocation := NewTransactionLocationGenerator() 3401 nextScriptLocation := NewScriptLocationGenerator() 3402 3403 // Deploy contracts 3404 3405 deployContracts( 3406 t, 3407 rt, 3408 contractsAddress, 3409 runtimeInterface, 3410 transactionEnvironment, 3411 nextTransactionLocation, 3412 ) 3413 3414 // reset events 3415 events = make([]cadence.Event, 0) 3416 3417 // Run script 3418 actual, err := rt.ExecuteScript( 3419 runtime.Script{ 3420 Source: script, 3421 }, 3422 runtime.Context{ 3423 Interface: runtimeInterface, 3424 Environment: scriptEnvironment, 3425 Location: nextScriptLocation(), 3426 }, 3427 ) 3428 require.NoError(t, err) 3429 3430 expected := cadence.NewArray([]cadence.Value{ 3431 cadence.UInt8(4), cadence.UInt8(0), 3432 cadence.UInt8(0), cadence.UInt8(0), 3433 cadence.UInt8(0), cadence.UInt8(0), 3434 cadence.UInt8(0), cadence.UInt8(0), 3435 cadence.UInt8(0), cadence.UInt8(0), 3436 cadence.UInt8(0), cadence.UInt8(0), 3437 cadence.UInt8(0), cadence.UInt8(0), 3438 cadence.UInt8(0), cadence.UInt8(0), 3439 cadence.UInt8(0), cadence.UInt8(0), 3440 cadence.UInt8(0), cadence.UInt8(0), 3441 }).WithType(cadence.NewConstantSizedArrayType( 3442 types.AddressLength, 3443 cadence.UInt8Type, 3444 )) 3445 3446 require.Equal(t, expected, actual) 3447 3448 // check deposit event 3449 expectedEventTypes := []string{ 3450 "EVM.CadenceOwnedAccountCreated", 3451 "EVM.CadenceOwnedAccountCreated", 3452 } 3453 CheckCadenceEventTypes(t, events, expectedEventTypes) 3454 3455 // check cadence owned account created events 3456 expectedCoaAddress := types.Address{3} 3457 requireEqualEventAddress(t, events[0], expectedCoaAddress) 3458 3459 expectedCoaAddress = types.Address{4} 3460 requireEqualEventAddress(t, events[1], expectedCoaAddress) 3461 } 3462 3463 func TestCadenceOwnedAccountCall(t *testing.T) { 3464 3465 t.Parallel() 3466 3467 expectedBalance, err := cadence.NewUFix64FromParts(1, 23000000) 3468 require.NoError(t, err) 3469 3470 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3471 3472 handler := &testContractHandler{ 3473 evmContractAddress: common.Address(contractsAddress), 3474 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 3475 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 3476 assert.True(t, isAuthorized) 3477 3478 return &testFlowAccount{ 3479 address: fromAddress, 3480 call: func( 3481 toAddress types.Address, 3482 data types.Data, 3483 limit types.GasLimit, 3484 balance types.Balance, 3485 ) *types.ResultSummary { 3486 assert.Equal(t, types.Address{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, toAddress) 3487 assert.Equal(t, types.Data{4, 5, 6}, data) 3488 assert.Equal(t, types.GasLimit(9999), limit) 3489 assert.Equal(t, types.NewBalanceFromUFix64(expectedBalance), balance) 3490 3491 return &types.ResultSummary{ 3492 Status: types.StatusSuccessful, 3493 ReturnedValue: types.Data{3, 1, 4}, 3494 } 3495 }, 3496 } 3497 }, 3498 } 3499 3500 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3501 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3502 3503 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3504 3505 script := []byte(` 3506 import EVM from 0x1 3507 3508 access(all) 3509 fun main(): [UInt8] { 3510 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 3511 let bal = EVM.Balance(attoflow: 0) 3512 bal.setFLOW(flow: 1.23) 3513 let response = cadenceOwnedAccount.call( 3514 to: EVM.EVMAddress( 3515 bytes: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 3516 ), 3517 data: [4, 5, 6], 3518 gasLimit: 9999, 3519 value: bal 3520 ) 3521 destroy cadenceOwnedAccount 3522 return response.data 3523 } 3524 `) 3525 3526 accountCodes := map[common.Location][]byte{} 3527 var events []cadence.Event 3528 3529 runtimeInterface := &TestRuntimeInterface{ 3530 Storage: NewTestLedger(nil, nil), 3531 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3532 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3533 }, 3534 OnResolveLocation: LocationResolver, 3535 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3536 accountCodes[location] = code 3537 return nil 3538 }, 3539 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3540 code = accountCodes[location] 3541 return code, nil 3542 }, 3543 OnEmitEvent: func(event cadence.Event) error { 3544 events = append(events, event) 3545 return nil 3546 }, 3547 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3548 return json.Decode(nil, b) 3549 }, 3550 } 3551 3552 nextTransactionLocation := NewTransactionLocationGenerator() 3553 nextScriptLocation := NewScriptLocationGenerator() 3554 3555 // Deploy contracts 3556 3557 deployContracts( 3558 t, 3559 rt, 3560 contractsAddress, 3561 runtimeInterface, 3562 transactionEnvironment, 3563 nextTransactionLocation, 3564 ) 3565 3566 // Run script 3567 3568 actual, err := rt.ExecuteScript( 3569 runtime.Script{ 3570 Source: script, 3571 }, 3572 runtime.Context{ 3573 Interface: runtimeInterface, 3574 Environment: scriptEnvironment, 3575 Location: nextScriptLocation(), 3576 }, 3577 ) 3578 require.NoError(t, err) 3579 3580 expected := cadence.NewArray([]cadence.Value{ 3581 cadence.UInt8(3), 3582 cadence.UInt8(1), 3583 cadence.UInt8(4), 3584 }).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 3585 3586 require.Equal(t, expected, actual) 3587 } 3588 3589 func TestEVMAddressDeposit(t *testing.T) { 3590 3591 t.Parallel() 3592 3593 expectedBalanceInUFix64, err := cadence.NewUFix64FromParts(1, 23000000) 3594 require.NoError(t, err) 3595 expectedBalance := types.NewBalanceFromUFix64(expectedBalanceInUFix64) 3596 3597 var deposited bool 3598 3599 handler := &testContractHandler{ 3600 3601 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 3602 assert.Equal(t, types.Address{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 3603 assert.False(t, isAuthorized) 3604 3605 return &testFlowAccount{ 3606 address: fromAddress, 3607 deposit: func(vault *types.FLOWTokenVault) { 3608 deposited = true 3609 assert.Equal( 3610 t, 3611 expectedBalance, 3612 vault.Balance(), 3613 ) 3614 }, 3615 } 3616 }, 3617 } 3618 3619 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3620 3621 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3622 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3623 3624 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3625 3626 script := []byte(` 3627 import EVM from 0x1 3628 import FlowToken from 0x1 3629 3630 access(all) 3631 fun main() { 3632 let admin = getAuthAccount<auth(Storage) &Account>(0x1) 3633 .storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)! 3634 let minter <- admin.createNewMinter(allowedAmount: 1.23) 3635 let vault <- minter.mintTokens(amount: 1.23) 3636 destroy minter 3637 3638 let address = EVM.EVMAddress( 3639 bytes: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 3640 ) 3641 address.deposit(from: <-vault) 3642 } 3643 `) 3644 3645 accountCodes := map[common.Location][]byte{} 3646 var events []cadence.Event 3647 3648 runtimeInterface := &TestRuntimeInterface{ 3649 Storage: NewTestLedger(nil, nil), 3650 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3651 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3652 }, 3653 OnResolveLocation: LocationResolver, 3654 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3655 accountCodes[location] = code 3656 return nil 3657 }, 3658 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3659 code = accountCodes[location] 3660 return code, nil 3661 }, 3662 OnEmitEvent: func(event cadence.Event) error { 3663 events = append(events, event) 3664 return nil 3665 }, 3666 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3667 return json.Decode(nil, b) 3668 }, 3669 } 3670 3671 nextTransactionLocation := NewTransactionLocationGenerator() 3672 nextScriptLocation := NewScriptLocationGenerator() 3673 3674 // Deploy contracts 3675 3676 deployContracts( 3677 t, 3678 rt, 3679 contractsAddress, 3680 runtimeInterface, 3681 transactionEnvironment, 3682 nextTransactionLocation, 3683 ) 3684 3685 // Run script 3686 3687 _, err = rt.ExecuteScript( 3688 runtime.Script{ 3689 Source: script, 3690 }, 3691 runtime.Context{ 3692 Interface: runtimeInterface, 3693 Environment: scriptEnvironment, 3694 Location: nextScriptLocation(), 3695 }, 3696 ) 3697 require.NoError(t, err) 3698 3699 require.True(t, deposited) 3700 } 3701 3702 func TestCOADeposit(t *testing.T) { 3703 3704 t.Parallel() 3705 3706 expectedBalance, err := cadence.NewUFix64FromParts(1, 23000000) 3707 require.NoError(t, err) 3708 3709 var deposited bool 3710 3711 var expectedCoaAddress = types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 3712 3713 handler := &testContractHandler{ 3714 3715 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 3716 assert.Equal(t, expectedCoaAddress, fromAddress) 3717 assert.False(t, isAuthorized) 3718 3719 return &testFlowAccount{ 3720 address: fromAddress, 3721 deposit: func(vault *types.FLOWTokenVault) { 3722 deposited = true 3723 assert.Equal( 3724 t, 3725 types.NewBalanceFromUFix64(expectedBalance), 3726 vault.Balance(), 3727 ) 3728 }, 3729 } 3730 }, 3731 } 3732 3733 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3734 3735 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3736 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3737 3738 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3739 3740 script := []byte(` 3741 import EVM from 0x1 3742 import FlowToken from 0x1 3743 3744 access(all) 3745 fun main() { 3746 let admin = getAuthAccount<auth(BorrowValue) &Account>(0x1) 3747 .storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)! 3748 let minter <- admin.createNewMinter(allowedAmount: 1.23) 3749 let vault <- minter.mintTokens(amount: 1.23) 3750 destroy minter 3751 3752 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 3753 cadenceOwnedAccount.deposit(from: <-vault) 3754 destroy cadenceOwnedAccount 3755 } 3756 `) 3757 3758 accountCodes := map[common.Location][]byte{} 3759 var events []cadence.Event 3760 3761 runtimeInterface := &TestRuntimeInterface{ 3762 Storage: NewTestLedger(nil, nil), 3763 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3764 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3765 }, 3766 OnResolveLocation: LocationResolver, 3767 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3768 accountCodes[location] = code 3769 return nil 3770 }, 3771 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3772 code = accountCodes[location] 3773 return code, nil 3774 }, 3775 OnEmitEvent: func(event cadence.Event) error { 3776 events = append(events, event) 3777 return nil 3778 }, 3779 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3780 return json.Decode(nil, b) 3781 }, 3782 } 3783 3784 nextTransactionLocation := NewTransactionLocationGenerator() 3785 nextScriptLocation := NewScriptLocationGenerator() 3786 3787 // Deploy contracts 3788 3789 deployContracts( 3790 t, 3791 rt, 3792 contractsAddress, 3793 runtimeInterface, 3794 transactionEnvironment, 3795 nextTransactionLocation, 3796 ) 3797 3798 // Run script 3799 3800 // reset events before script execution 3801 events = make([]cadence.Event, 0) 3802 3803 _, err = rt.ExecuteScript( 3804 runtime.Script{ 3805 Source: script, 3806 }, 3807 runtime.Context{ 3808 Interface: runtimeInterface, 3809 Environment: scriptEnvironment, 3810 Location: nextScriptLocation(), 3811 }, 3812 ) 3813 require.NoError(t, err) 3814 3815 require.True(t, deposited) 3816 3817 // check deposit event 3818 expectedEventTypes := []string{ 3819 "FlowToken.MinterCreated", 3820 "FlowToken.TokensMinted", 3821 "EVM.CadenceOwnedAccountCreated", 3822 "EVM.FLOWTokensDeposited", 3823 } 3824 CheckCadenceEventTypes(t, events, expectedEventTypes) 3825 3826 // token deposit event 3827 tokenDepositEvent := events[3] 3828 tokenDepositEventFields := cadence.FieldsMappedByName(tokenDepositEvent) 3829 3830 requireEqualEventAddress(t, tokenDepositEvent, expectedCoaAddress) 3831 3832 // check amount 3833 require.Equal(t, 3834 expectedBalance, 3835 tokenDepositEventFields["amount"], 3836 ) 3837 } 3838 3839 func TestCadenceOwnedAccountWithdraw(t *testing.T) { 3840 3841 t.Parallel() 3842 3843 expectedDepositBalance, err := cadence.NewUFix64FromParts(2, 34000000) 3844 require.NoError(t, err) 3845 3846 expectedWithdrawBalance, err := cadence.NewUFix64FromParts(1, 23000000) 3847 require.NoError(t, err) 3848 3849 var deposited bool 3850 var withdrew bool 3851 3852 contractsAddress := flow.BytesToAddress([]byte{0x1}) 3853 3854 var nextUUID uint64 = 1 3855 3856 var expectedCoaAddress = types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 3857 3858 handler := &testContractHandler{ 3859 flowTokenAddress: common.Address(contractsAddress), 3860 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 3861 assert.Equal(t, expectedCoaAddress, fromAddress) 3862 assert.Equal(t, deposited, isAuthorized) 3863 3864 return &testFlowAccount{ 3865 address: fromAddress, 3866 deposit: func(vault *types.FLOWTokenVault) { 3867 deposited = true 3868 assert.Equal(t, 3869 types.NewBalanceFromUFix64(expectedDepositBalance), 3870 vault.Balance(), 3871 ) 3872 }, 3873 withdraw: func(balance types.Balance) *types.FLOWTokenVault { 3874 assert.Equal(t, 3875 types.NewBalanceFromUFix64(expectedWithdrawBalance), 3876 balance, 3877 ) 3878 withdrew = true 3879 return types.NewFlowTokenVault(balance) 3880 }, 3881 } 3882 }, 3883 generateResourceUUID: func() uint64 { 3884 uuid := nextUUID 3885 nextUUID++ 3886 return uuid 3887 }, 3888 } 3889 3890 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 3891 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 3892 3893 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 3894 3895 script := []byte(` 3896 import EVM from 0x1 3897 import FlowToken from 0x1 3898 3899 access(all) 3900 fun main(): UFix64 { 3901 let admin = getAuthAccount<auth(BorrowValue) &Account>(0x1) 3902 .storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)! 3903 let minter <- admin.createNewMinter(allowedAmount: 2.34) 3904 let vault <- minter.mintTokens(amount: 2.34) 3905 destroy minter 3906 3907 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 3908 cadenceOwnedAccount.deposit(from: <-vault) 3909 3910 let vault2 <- cadenceOwnedAccount.withdraw(balance: EVM.Balance(attoflow: 1230000000000000000)) 3911 let balance = vault2.balance 3912 log(vault2.uuid) 3913 3914 destroy cadenceOwnedAccount 3915 destroy vault2 3916 3917 return balance 3918 } 3919 `) 3920 3921 accountCodes := map[common.Location][]byte{} 3922 var events []cadence.Event 3923 var logs []string 3924 3925 runtimeInterface := &TestRuntimeInterface{ 3926 Storage: NewTestLedger(nil, nil), 3927 OnGetSigningAccounts: func() ([]runtime.Address, error) { 3928 return []runtime.Address{runtime.Address(contractsAddress)}, nil 3929 }, 3930 OnResolveLocation: LocationResolver, 3931 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 3932 accountCodes[location] = code 3933 return nil 3934 }, 3935 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 3936 code = accountCodes[location] 3937 return code, nil 3938 }, 3939 OnEmitEvent: func(event cadence.Event) error { 3940 events = append(events, event) 3941 return nil 3942 }, 3943 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 3944 return json.Decode(nil, b) 3945 }, 3946 OnProgramLog: func(s string) { 3947 logs = append(logs, s) 3948 }, 3949 } 3950 3951 nextTransactionLocation := NewTransactionLocationGenerator() 3952 nextScriptLocation := NewScriptLocationGenerator() 3953 3954 // Deploy contracts 3955 3956 deployContracts( 3957 t, 3958 rt, 3959 contractsAddress, 3960 runtimeInterface, 3961 transactionEnvironment, 3962 nextTransactionLocation, 3963 ) 3964 3965 // reset events 3966 events = make([]cadence.Event, 0) 3967 // Run script 3968 result, err := rt.ExecuteScript( 3969 runtime.Script{ 3970 Source: script, 3971 }, 3972 runtime.Context{ 3973 Interface: runtimeInterface, 3974 Environment: scriptEnvironment, 3975 Location: nextScriptLocation(), 3976 }, 3977 ) 3978 require.NoError(t, err) 3979 3980 assert.True(t, deposited) 3981 assert.True(t, withdrew) 3982 assert.Equal(t, expectedWithdrawBalance, result) 3983 3984 assert.Equal(t, []string{"1"}, logs) 3985 3986 // check deposit event 3987 expectedEventTypes := []string{ 3988 "FlowToken.MinterCreated", 3989 "FlowToken.TokensMinted", 3990 "EVM.CadenceOwnedAccountCreated", 3991 "EVM.FLOWTokensDeposited", 3992 "EVM.FLOWTokensWithdrawn", 3993 } 3994 CheckCadenceEventTypes(t, events, expectedEventTypes) 3995 3996 // token deposit event 3997 tokenWithdrawEvent := events[4] 3998 tokenWithdrawEventFields := cadence.FieldsMappedByName(tokenWithdrawEvent) 3999 4000 requireEqualEventAddress(t, tokenWithdrawEvent, expectedCoaAddress) 4001 4002 // check amount 4003 require.Equal(t, 4004 expectedWithdrawBalance, 4005 tokenWithdrawEventFields["amount"], 4006 ) 4007 } 4008 4009 func TestCadenceOwnedAccountDeploy(t *testing.T) { 4010 4011 t.Parallel() 4012 4013 var deployed bool 4014 4015 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4016 4017 expectedBalance, err := cadence.NewUFix64FromParts(1, 23000000) 4018 require.NoError(t, err) 4019 4020 handler := &testContractHandler{ 4021 evmContractAddress: common.Address(contractsAddress), 4022 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 4023 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 4024 assert.True(t, isAuthorized) 4025 4026 return &testFlowAccount{ 4027 address: fromAddress, 4028 deploy: func(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary { 4029 deployed = true 4030 assert.Equal(t, types.Code{4, 5, 6}, code) 4031 assert.Equal(t, types.GasLimit(9999), limit) 4032 assert.Equal(t, types.NewBalanceFromUFix64(expectedBalance), balance) 4033 4034 return &types.ResultSummary{ 4035 Status: types.StatusSuccessful, 4036 DeployedContractAddress: &types.Address{4}, 4037 ReturnedValue: types.Data{5}, 4038 } 4039 }, 4040 } 4041 }, 4042 } 4043 4044 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 4045 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 4046 4047 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 4048 4049 script := []byte(` 4050 import EVM from 0x1 4051 4052 access(all) 4053 fun main(): [UInt8] { 4054 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4055 let res = cadenceOwnedAccount.deploy( 4056 code: [4, 5, 6], 4057 gasLimit: 9999, 4058 value: EVM.Balance(attoflow: 1230000000000000000) 4059 ) 4060 destroy cadenceOwnedAccount 4061 4062 assert(res.deployedContract?.bytes == [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 4063 return res.data 4064 } 4065 `) 4066 4067 accountCodes := map[common.Location][]byte{} 4068 var events []cadence.Event 4069 4070 runtimeInterface := &TestRuntimeInterface{ 4071 Storage: NewTestLedger(nil, nil), 4072 OnGetSigningAccounts: func() ([]runtime.Address, error) { 4073 return []runtime.Address{runtime.Address(contractsAddress)}, nil 4074 }, 4075 OnResolveLocation: LocationResolver, 4076 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 4077 accountCodes[location] = code 4078 return nil 4079 }, 4080 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 4081 code = accountCodes[location] 4082 return code, nil 4083 }, 4084 OnEmitEvent: func(event cadence.Event) error { 4085 events = append(events, event) 4086 return nil 4087 }, 4088 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 4089 return json.Decode(nil, b) 4090 }, 4091 } 4092 4093 nextTransactionLocation := NewTransactionLocationGenerator() 4094 nextScriptLocation := NewScriptLocationGenerator() 4095 4096 // Deploy contracts 4097 4098 deployContracts( 4099 t, 4100 rt, 4101 contractsAddress, 4102 runtimeInterface, 4103 transactionEnvironment, 4104 nextTransactionLocation, 4105 ) 4106 4107 // Run script 4108 4109 actual, err := rt.ExecuteScript( 4110 runtime.Script{ 4111 Source: script, 4112 }, 4113 runtime.Context{ 4114 Interface: runtimeInterface, 4115 Environment: scriptEnvironment, 4116 Location: nextScriptLocation(), 4117 }, 4118 ) 4119 require.NoError(t, err) 4120 4121 expected := cadence. 4122 NewArray([]cadence.Value{cadence.UInt8(5)}). 4123 WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 4124 4125 require.Equal(t, expected, actual) 4126 4127 require.True(t, deployed) 4128 } 4129 4130 func RunEVMScript( 4131 t *testing.T, 4132 handler *testContractHandler, 4133 script []byte, 4134 expectedValue cadence.Value, 4135 ) { 4136 contractsAddress := flow.Address(handler.evmContractAddress) 4137 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 4138 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 4139 4140 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 4141 4142 accountCodes := map[common.Location][]byte{} 4143 var events []cadence.Event 4144 4145 runtimeInterface := &TestRuntimeInterface{ 4146 Storage: NewTestLedger(nil, nil), 4147 OnGetSigningAccounts: func() ([]runtime.Address, error) { 4148 return []runtime.Address{runtime.Address(contractsAddress)}, nil 4149 }, 4150 OnResolveLocation: LocationResolver, 4151 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 4152 accountCodes[location] = code 4153 return nil 4154 }, 4155 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 4156 code = accountCodes[location] 4157 return code, nil 4158 }, 4159 OnEmitEvent: func(event cadence.Event) error { 4160 events = append(events, event) 4161 return nil 4162 }, 4163 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 4164 return json.Decode(nil, b) 4165 }, 4166 } 4167 4168 nextTransactionLocation := NewTransactionLocationGenerator() 4169 nextScriptLocation := NewScriptLocationGenerator() 4170 4171 // Deploy contracts 4172 4173 deployContracts( 4174 t, 4175 rt, 4176 contractsAddress, 4177 runtimeInterface, 4178 transactionEnvironment, 4179 nextTransactionLocation, 4180 ) 4181 4182 // Run script 4183 4184 actual, err := rt.ExecuteScript( 4185 runtime.Script{ 4186 Source: script, 4187 }, 4188 runtime.Context{ 4189 Interface: runtimeInterface, 4190 Environment: scriptEnvironment, 4191 Location: nextScriptLocation(), 4192 }, 4193 ) 4194 require.NoError(t, err) 4195 4196 require.Equal(t, expectedValue, actual) 4197 } 4198 4199 func TestEVMAccountBalance(t *testing.T) { 4200 t.Parallel() 4201 4202 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4203 expectedBalanceValue := cadence.NewUInt(1013370000000000000) 4204 expectedBalance := cadence. 4205 NewStruct([]cadence.Value{expectedBalanceValue}). 4206 WithType(stdlib.NewBalanceCadenceType(common.Address(contractsAddress))) 4207 4208 handler := &testContractHandler{ 4209 flowTokenAddress: common.Address(contractsAddress), 4210 evmContractAddress: common.Address(contractsAddress), 4211 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 4212 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 4213 assert.False(t, isAuthorized) 4214 4215 return &testFlowAccount{ 4216 address: fromAddress, 4217 balance: func() types.Balance { 4218 return types.NewBalance(expectedBalanceValue.Value) 4219 }, 4220 } 4221 }, 4222 } 4223 4224 script := []byte(` 4225 import EVM from 0x1 4226 4227 access(all) 4228 fun main(): EVM.Balance { 4229 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4230 let balance = cadenceOwnedAccount.balance() 4231 destroy cadenceOwnedAccount 4232 return balance 4233 } 4234 `) 4235 RunEVMScript(t, handler, script, expectedBalance) 4236 } 4237 4238 func TestEVMAccountNonce(t *testing.T) { 4239 t.Parallel() 4240 4241 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4242 expectedNonceValue := cadence.NewUInt64(2000) 4243 handler := &testContractHandler{ 4244 flowTokenAddress: common.Address(contractsAddress), 4245 evmContractAddress: common.Address(contractsAddress), 4246 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 4247 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 4248 assert.False(t, isAuthorized) 4249 4250 return &testFlowAccount{ 4251 address: fromAddress, 4252 nonce: func() uint64 { 4253 return uint64(expectedNonceValue) 4254 }, 4255 } 4256 }, 4257 } 4258 4259 script := []byte(` 4260 import EVM from 0x1 4261 4262 access(all) 4263 fun main(): UInt64 { 4264 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4265 let nonce = cadenceOwnedAccount.address().nonce() 4266 destroy cadenceOwnedAccount 4267 return nonce 4268 } 4269 `) 4270 4271 RunEVMScript(t, handler, script, expectedNonceValue) 4272 } 4273 4274 func TestEVMAccountCode(t *testing.T) { 4275 t.Parallel() 4276 4277 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4278 expectedCodeRaw := []byte{1, 2, 3} 4279 expectedCodeValue := cadence.NewArray( 4280 []cadence.Value{cadence.UInt8(1), cadence.UInt8(2), cadence.UInt8(3)}, 4281 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 4282 4283 handler := &testContractHandler{ 4284 flowTokenAddress: common.Address(contractsAddress), 4285 evmContractAddress: common.Address(contractsAddress), 4286 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 4287 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 4288 assert.False(t, isAuthorized) 4289 4290 return &testFlowAccount{ 4291 address: fromAddress, 4292 code: func() types.Code { 4293 return expectedCodeRaw 4294 }, 4295 } 4296 }, 4297 } 4298 4299 script := []byte(` 4300 import EVM from 0x1 4301 4302 access(all) 4303 fun main(): [UInt8] { 4304 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4305 let code = cadenceOwnedAccount.address().code() 4306 destroy cadenceOwnedAccount 4307 return code 4308 } 4309 `) 4310 4311 RunEVMScript(t, handler, script, expectedCodeValue) 4312 } 4313 4314 func TestEVMAccountCodeHash(t *testing.T) { 4315 t.Parallel() 4316 4317 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4318 expectedCodeHashRaw := []byte{1, 2, 3} 4319 expectedCodeHashValue := cadence.NewArray( 4320 []cadence.Value{cadence.UInt8(1), cadence.UInt8(2), cadence.UInt8(3)}, 4321 ).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 4322 4323 handler := &testContractHandler{ 4324 flowTokenAddress: common.Address(contractsAddress), 4325 evmContractAddress: common.Address(contractsAddress), 4326 accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { 4327 assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) 4328 assert.False(t, isAuthorized) 4329 4330 return &testFlowAccount{ 4331 address: fromAddress, 4332 codeHash: func() []byte { 4333 return expectedCodeHashRaw 4334 }, 4335 } 4336 }, 4337 } 4338 4339 script := []byte(` 4340 import EVM from 0x1 4341 4342 access(all) 4343 fun main(): [UInt8] { 4344 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4345 let codeHash = cadenceOwnedAccount.address().codeHash() 4346 destroy cadenceOwnedAccount 4347 return codeHash 4348 } 4349 `) 4350 4351 RunEVMScript(t, handler, script, expectedCodeHashValue) 4352 } 4353 4354 func TestEVMValidateCOAOwnershipProof(t *testing.T) { 4355 t.Parallel() 4356 4357 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4358 4359 proof := &types.COAOwnershipProofInContext{ 4360 COAOwnershipProof: types.COAOwnershipProof{ 4361 Address: types.FlowAddress(contractsAddress), 4362 CapabilityPath: "coa", 4363 Signatures: []types.Signature{[]byte("signature")}, 4364 KeyIndices: []uint64{0}, 4365 }, 4366 SignedData: []byte("signedData"), 4367 EVMAddress: RandomAddress(t), 4368 } 4369 4370 handler := &testContractHandler{ 4371 deployCOA: func(_ uint64) types.Address { 4372 return proof.EVMAddress 4373 }, 4374 } 4375 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 4376 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 4377 4378 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 4379 4380 accountCodes := map[common.Location][]byte{} 4381 var events []cadence.Event 4382 4383 runtimeInterface := &TestRuntimeInterface{ 4384 Storage: NewTestLedger(nil, nil), 4385 OnGetSigningAccounts: func() ([]runtime.Address, error) { 4386 return []runtime.Address{runtime.Address(contractsAddress)}, nil 4387 }, 4388 OnResolveLocation: LocationResolver, 4389 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 4390 accountCodes[location] = code 4391 return nil 4392 }, 4393 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 4394 code = accountCodes[location] 4395 return code, nil 4396 }, 4397 OnEmitEvent: func(event cadence.Event) error { 4398 events = append(events, event) 4399 return nil 4400 }, 4401 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 4402 return json.Decode(nil, b) 4403 }, 4404 OnGetAccountKey: func(addr runtime.Address, index int) (*cadenceStdlib.AccountKey, error) { 4405 require.Equal(t, proof.Address[:], addr[:]) 4406 return &cadenceStdlib.AccountKey{ 4407 PublicKey: &cadenceStdlib.PublicKey{}, 4408 KeyIndex: index, 4409 Weight: 100, 4410 HashAlgo: sema.HashAlgorithmKECCAK_256, 4411 IsRevoked: false, 4412 }, nil 4413 }, 4414 OnVerifySignature: func( 4415 signature []byte, 4416 tag string, 4417 sd, 4418 publicKey []byte, 4419 signatureAlgorithm runtime.SignatureAlgorithm, 4420 hashAlgorithm runtime.HashAlgorithm) (bool, error) { 4421 // require.Equal(t, []byte(signedData.ToGoValue()), st) 4422 return true, nil 4423 }, 4424 } 4425 4426 nextTransactionLocation := NewTransactionLocationGenerator() 4427 nextScriptLocation := NewScriptLocationGenerator() 4428 4429 // Deploy contracts 4430 4431 deployContracts( 4432 t, 4433 rt, 4434 contractsAddress, 4435 runtimeInterface, 4436 transactionEnvironment, 4437 nextTransactionLocation, 4438 ) 4439 4440 setupTx := []byte(` 4441 import EVM from 0x1 4442 4443 transaction { 4444 prepare(account: auth(Capabilities, SaveValue) &Account) { 4445 let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount() 4446 4447 account.storage.save( 4448 <-cadenceOwnedAccount, 4449 to: /storage/coa 4450 ) 4451 4452 let cap = account.capabilities.storage 4453 .issue<&EVM.CadenceOwnedAccount>(/storage/coa) 4454 account.capabilities.publish(cap, at: /public/coa) 4455 } 4456 }`) 4457 4458 err := rt.ExecuteTransaction( 4459 runtime.Script{ 4460 Source: setupTx, 4461 }, 4462 runtime.Context{ 4463 Interface: runtimeInterface, 4464 Environment: transactionEnvironment, 4465 Location: nextTransactionLocation(), 4466 }, 4467 ) 4468 require.NoError(t, err) 4469 4470 script := []byte(` 4471 import EVM from 0x1 4472 4473 access(all) 4474 fun main( 4475 address: Address, 4476 path: PublicPath, 4477 signedData: [UInt8], 4478 keyIndices: [UInt64], 4479 signatures: [[UInt8]], 4480 evmAddress: [UInt8; 20] 4481 4482 ) { 4483 EVM.validateCOAOwnershipProof( 4484 address: address, 4485 path: path, 4486 signedData: signedData, 4487 keyIndices: keyIndices, 4488 signatures: signatures, 4489 evmAddress: evmAddress 4490 ) 4491 } 4492 `) 4493 4494 // Run script 4495 _, err = rt.ExecuteScript( 4496 runtime.Script{ 4497 Source: script, 4498 Arguments: EncodeArgs(proof.ToCadenceValues()), 4499 }, 4500 runtime.Context{ 4501 Interface: runtimeInterface, 4502 Environment: scriptEnvironment, 4503 Location: nextScriptLocation(), 4504 }, 4505 ) 4506 require.NoError(t, err) 4507 } 4508 4509 func TestInternalEVMAccess(t *testing.T) { 4510 4511 t.Parallel() 4512 4513 handler := &testContractHandler{} 4514 4515 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4516 transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) 4517 scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) 4518 rt := runtime.NewInterpreterRuntime(runtime.Config{}) 4519 4520 script := []byte(` 4521 import EVM from 0x1 4522 4523 access(all) 4524 fun main() { 4525 let a = InternalEVM.createBridgedAccount() 4526 } 4527 `) 4528 4529 accountCodes := map[common.Location][]byte{} 4530 4531 runtimeInterface := &TestRuntimeInterface{ 4532 Storage: NewTestLedger(nil, nil), 4533 OnGetSigningAccounts: func() ([]runtime.Address, error) { 4534 return []runtime.Address{runtime.Address(contractsAddress)}, nil 4535 }, 4536 OnResolveLocation: LocationResolver, 4537 OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { 4538 accountCodes[location] = code 4539 return nil 4540 }, 4541 OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { 4542 code = accountCodes[location] 4543 return code, nil 4544 }, 4545 OnEmitEvent: func(event cadence.Event) error { 4546 return nil 4547 }, 4548 OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { 4549 return json.Decode(nil, b) 4550 }, 4551 } 4552 4553 nextTransactionLocation := NewTransactionLocationGenerator() 4554 nextScriptLocation := NewScriptLocationGenerator() 4555 4556 // Deploy contracts 4557 4558 deployContracts( 4559 t, 4560 rt, 4561 contractsAddress, 4562 runtimeInterface, 4563 transactionEnvironment, 4564 nextTransactionLocation, 4565 ) 4566 4567 // Run script 4568 4569 _, err := rt.ExecuteScript( 4570 runtime.Script{ 4571 Source: script, 4572 }, 4573 runtime.Context{ 4574 Interface: runtimeInterface, 4575 Environment: scriptEnvironment, 4576 Location: nextScriptLocation(), 4577 }, 4578 ) 4579 require.Error(t, err) 4580 } 4581 4582 func TestEVMGetLatestBlock(t *testing.T) { 4583 t.Parallel() 4584 4585 contractsAddress := flow.BytesToAddress([]byte{0x1}) 4586 4587 latestBlock := &types.Block{ 4588 Height: uint64(2), 4589 TotalSupply: big.NewInt(1500000000000000000), 4590 Timestamp: uint64(1337), 4591 } 4592 handler := &testContractHandler{ 4593 evmContractAddress: common.Address(contractsAddress), 4594 lastExecutedBlock: func() *types.Block { 4595 return latestBlock 4596 }, 4597 } 4598 4599 script := []byte(` 4600 import EVM from 0x1 4601 4602 access(all) 4603 fun main(): EVM.EVMBlock { 4604 return EVM.getLatestBlock() 4605 } 4606 `) 4607 4608 evmBlockCadenceType := stdlib.NewEVMBlockCadenceType( 4609 common.Address(contractsAddress), 4610 ) 4611 4612 blockHeight := cadence.NewUInt64(latestBlock.Height) 4613 hash, err := latestBlock.Hash() 4614 require.NoError(t, err) 4615 blockHash, err := cadence.NewString(hash.Hex()) 4616 require.NoError(t, err) 4617 blockTotalSupply := cadence.NewIntFromBig(latestBlock.TotalSupply) 4618 timestamp := cadence.NewUInt64(latestBlock.Timestamp) 4619 4620 expectedEVMBlock := cadence.NewStruct([]cadence.Value{ 4621 blockHeight, 4622 blockHash, 4623 blockTotalSupply, 4624 timestamp, 4625 }).WithType(evmBlockCadenceType) 4626 4627 RunEVMScript(t, handler, script, expectedEVMBlock) 4628 }