Browse Source

Represent contracts by their program id (#1474)

Lucas Steuernagel 2 years ago
parent
commit
d5e72894c3
100 changed files with 1682 additions and 1786 deletions
  1. 1 0
      Cargo.toml
  2. 1 1
      docs/examples/solana/contract_address.sol
  3. 0 23
      docs/examples/solana/contract_new.sol
  4. 4 4
      docs/examples/solana/payer_annotation.sol
  5. 3 3
      docs/examples/solana/program_id.sol
  6. 0 4
      docs/language/builtins.rst
  7. 8 4
      docs/language/contracts.rst
  8. 2 2
      docs/language/expressions.rst
  9. 2 1
      docs/language/managing_values.rst
  10. 5 3
      docs/targets/solana.rst
  11. 1 1
      integration/anchor/tests/anchor.ts
  12. 1 1
      integration/polkadot/call_flags.sol
  13. 1 1
      integration/polkadot/issue666.sol
  14. 0 2
      integration/solana/balances.spec.ts
  15. 0 2
      integration/solana/builtins.spec.ts
  16. 21 30
      integration/solana/calls.spec.ts
  17. 10 11
      integration/solana/create_contract.sol
  18. 19 28
      integration/solana/create_contract.spec.ts
  19. 0 1
      integration/solana/events.spec.ts
  20. 9 9
      integration/solana/runtime_errors.spec.ts
  21. 42 42
      integration/solana/simple.spec.ts
  22. 0 1
      integration/solana/simple_collectible.spec.ts
  23. 0 13
      integration/solana/system_instruction.spec.ts
  24. 0 9
      integration/solana/token.spec.ts
  25. 0 2
      integration/solana/verify_sig.spec.ts
  26. 149 503
      src/abi/tests.rs
  27. 0 3
      src/bin/languageserver/mod.rs
  28. 7 1
      src/codegen/cfg.rs
  29. 2 0
      src/codegen/constant_folding.rs
  30. 14 4
      src/codegen/constructor.rs
  31. 11 4
      src/codegen/dispatch/solana.rs
  32. 14 1
      src/codegen/expression.rs
  33. 1 2
      src/codegen/mod.rs
  34. 115 86
      src/codegen/solana_accounts/account_collection.rs
  35. 101 78
      src/codegen/solana_accounts/account_management.rs
  36. 38 19
      src/codegen/solana_deploy.rs
  37. 1 0
      src/codegen/statements/try_catch.rs
  38. 2 0
      src/codegen/subexpression_elimination/instruction.rs
  39. 3 5
      src/emit/solana/mod.rs
  40. 19 61
      src/emit/solana/target.rs
  41. 19 4
      src/sema/ast.rs
  42. 1 12
      src/sema/builtin.rs
  43. 3 6
      src/sema/contracts.rs
  44. 0 3
      src/sema/dotgraphviz.rs
  45. 48 10
      src/sema/expression/constructor.rs
  46. 17 73
      src/sema/expression/function_call.rs
  47. 4 0
      src/sema/expression/member_access.rs
  48. 20 0
      src/sema/expression/mod.rs
  49. 6 0
      src/sema/function_annotation.rs
  50. 102 9
      src/sema/mutability.rs
  51. 2 0
      src/sema/namespace.rs
  52. 9 4
      src/sema/solana_accounts.rs
  53. 15 7
      src/sema/statements.rs
  54. 224 0
      src/sema/tests/data_account.rs
  55. 6 3
      src/sema/tests/mod.rs
  56. 0 3
      src/sema/unused_variable.rs
  57. 3 5
      src/sema/variables.rs
  58. 12 81
      src/sema/yul/tests/expression.rs
  59. 7 53
      stdlib/solana.c
  60. 3 3
      tests/codegen_testcases/solidity/constructor_with_metas.sol
  61. 3 3
      tests/codegen_testcases/solidity/solana_bump.sol
  62. 9 8
      tests/codegen_testcases/solidity/solana_payer_account.sol
  63. 1 1
      tests/codegen_testcases/solidity/unused_variable_elimination.sol
  64. 1 1
      tests/contract_testcases/solana/account_meta.sol
  65. 123 0
      tests/contract_testcases/solana/accounts/constructor_in_loop.sol
  66. 26 0
      tests/contract_testcases/solana/accounts/data_account.sol
  67. 8 0
      tests/contract_testcases/solana/accounts/data_account_visibility.sol
  68. 51 0
      tests/contract_testcases/solana/accounts/double_calls.sol
  69. 1 1
      tests/contract_testcases/solana/address_cast.sol
  70. 2 2
      tests/contract_testcases/solana/annotations/account_name_collision.sol
  71. 9 4
      tests/contract_testcases/solana/annotations/constructor_external_function.sol
  72. 1 1
      tests/contract_testcases/solana/call/call_args_three_ways.sol
  73. 1 1
      tests/contract_testcases/solana/expressions/contract_no_init.sol
  74. 2 2
      tests/contract_testcases/solana/mapping_deletion.sol
  75. 2 1
      tests/contract_testcases/solana/yul/yul_switch.sol
  76. 21 0
      tests/imports_testcases/Dummy.json
  77. 1 1
      tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol
  78. 1 1
      tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol
  79. 1 1
      tests/polkadot_tests/calls.rs
  80. 1 1
      tests/polkadot_tests/contracts.rs
  81. 1 1
      tests/polkadot_tests/yul.rs
  82. 7 1
      tests/solana.rs
  83. 5 15
      tests/solana_tests/abi.rs
  84. 2 13
      tests/solana_tests/abi_decode.rs
  85. 8 24
      tests/solana_tests/abi_encode.rs
  86. 11 19
      tests/solana_tests/accessor.rs
  87. 8 34
      tests/solana_tests/account_info.rs
  88. 3 5
      tests/solana_tests/account_serialization.rs
  89. 17 82
      tests/solana_tests/arrays.rs
  90. 144 72
      tests/solana_tests/balance.rs
  91. 9 38
      tests/solana_tests/builtin.rs
  92. 18 40
      tests/solana_tests/call.rs
  93. 2 10
      tests/solana_tests/constant.rs
  94. 60 87
      tests/solana_tests/create_contract.rs
  95. 1 9
      tests/solana_tests/destructure.rs
  96. 2 6
      tests/solana_tests/events.rs
  97. 5 26
      tests/solana_tests/expressions.rs
  98. 6 24
      tests/solana_tests/hash.rs
  99. 0 6
      tests/solana_tests/math.rs
  100. 0 4
      tests/solana_tests/metas.rs

+ 1 - 0
Cargo.toml

@@ -65,6 +65,7 @@ wasm-opt = { version = "0.112.0", optional = true }
 contract-build = { version = "3.0.1", optional = true }
 contract-build = { version = "3.0.1", optional = true }
 primitive-types = { version = "0.12", features = ["codec"] }
 primitive-types = { version = "0.12", features = ["codec"] }
 normalize-path = "0.2.1"
 normalize-path = "0.2.1"
+bitflags = "2.3.3"
 
 
 [dev-dependencies]
 [dev-dependencies]
 num-derive = "0.4"
 num-derive = "0.4"

+ 1 - 1
docs/examples/solana/contract_address.sol

@@ -10,6 +10,6 @@ contract hatchling {
 
 
 contract adult {
 contract adult {
     function test(address addr) external {
     function test(address addr) external {
-        hatchling h = new hatchling{address: addr}("luna");
+        hatchling h = new hatchling("luna");
     }
     }
 }
 }

+ 0 - 23
docs/examples/solana/contract_new.sol

@@ -1,23 +0,0 @@
-@program_id("8scvhNyoxUUo7e3hRnUzcTtFtcZ3LdXHuy8b42Hd5d2T")
-contract hatchling {
-    string name;
-    address private origin;
-
-    constructor(string id, address parent) {
-        require(id != "", "name must be provided");
-        name = id;
-        origin = parent;
-    }
-
-    function root() public returns (address) {
-        return origin;
-    }
-}
-
-contract creator {
-    function create_hatchling(address new_address) external {
-        hatchling h;
-       
-	h = new hatchling{address: new_address}("luna", address(this));
-    }
-}

+ 4 - 4
docs/examples/solana/payer_annotation.sol

@@ -3,10 +3,10 @@ import 'solana';
 @program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
 @program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
 contract Builder {
 contract Builder {
     BeingBuilt other;
     BeingBuilt other;
-    function build_this(address addr) external {
-        // When calling a constructor from an external function, the only call argument needed
-        // is the data account. The compiler automatically passes the necessary accounts to the call.
-        other = new BeingBuilt{address: addr}("my_seed");
+    function build_this() external {
+        // When calling a constructor from an external function, the data account for the contract
+        // 'BeingBuilt' should be passed as the 'BeingBuilt_dataAccount' in the client code.
+        other = new BeingBuilt("my_seed");
     }
     }
 
 
     function build_that(address data_account, address payer_account) public {
     function build_that(address data_account, address payer_account) public {

+ 3 - 3
docs/examples/solana/program_id.sol

@@ -8,11 +8,11 @@ contract Foo {
 contract Bar {
 contract Bar {
     Foo public foo;
     Foo public foo;
 
 
-    function create_foo(address new_address) external {
-        foo = new Foo{address: new_address}();
+    function create_foo() external {
+        foo = new Foo();
     }
     }
 
 
-    function call_foo() public pure {
+    function call_foo() public {
         foo.say_hello();
         foo.say_hello();
     }
     }
 }
 }

+ 0 - 4
docs/language/builtins.rst

@@ -108,10 +108,6 @@ AccountInfo[] ``tx.accounts``
 .. include:: ../examples/solana/accountinfo.sol
 .. include:: ../examples/solana/accountinfo.sol
   :code: solidity
   :code: solidity
 
 
-address ``tx.program_id``
-    The address or account of the currently executing program. Only available on
-    Solana.
-
 ``block`` properties
 ``block`` properties
 ++++++++++++++++++++++
 ++++++++++++++++++++++
 
 

+ 8 - 4
docs/language/contracts.rst

@@ -94,15 +94,19 @@ __________________________________
 
 
 On Solana, the contract being created must have the ``@program_id()`` annotation that specifies the program account to
 On Solana, the contract being created must have the ``@program_id()`` annotation that specifies the program account to
 which the contract code has been deployed. This account holds only the contract's executable binary.
 which the contract code has been deployed. This account holds only the contract's executable binary.
-When calling a constructor, one needs to provide an address that will serve as the contract's data account,
-by using the call argument ``address``:
+When calling a constructor only once from an external function, no call arguments are needed. The data account
+necessary to initialize the contract should be present in the IDL and is identified as ``contractName_dataAccount``.
+In the example below, the IDL for the instruction ``test`` requires the ``hatchling_dataAccount`` account to be
+initialized as the new contract's data account.
 
 
 .. include:: ../examples/solana/contract_address.sol
 .. include:: ../examples/solana/contract_address.sol
   :code: solidity
   :code: solidity
 
 
-When the contract's data account is passed through the ``address`` call argument, the compiler will automatically create
+When there are no call arguments to a constructor call, the compiler will automatically create
 the ``AccountMeta`` array the constructor call needs. Due to the impossibility to track account ordering in
 the ``AccountMeta`` array the constructor call needs. Due to the impossibility to track account ordering in
-private, internal and public functions, such a call argument is only allowed in external functions.
+private, internal and public functions, such a call argument is only allowed in functions with ``external``
+visibility. This automatic account management only works, however, if there is a single instantiation of
+a particular contract type.
 
 
 Alternatively, the data account to be initialized can be provided using the ``accounts`` call argument. In this case,
 Alternatively, the data account to be initialized can be provided using the ``accounts`` call argument. In this case,
 one needs to instantiate a fixed length array of type ``AccountMeta`` to pass to the call. The array must contain all
 one needs to instantiate a fixed length array of type ``AccountMeta`` to pass to the call. The array must contain all

+ 2 - 2
docs/language/expressions.rst

@@ -124,8 +124,8 @@ this only works with public functions.
 
 
 .. note::
 .. note::
 
 
-    On Solana, this gives the account of contract data. If you want the account with the program code,
-    use ``tx.program_id``.
+    On Solana, ``this`` returns the program account. If you are looking for the data account, please
+    use ``tx.accounts.dataAccount.key``.
 
 
 type(..) operators
 type(..) operators
 __________________
 __________________

+ 2 - 1
docs/language/managing_values.rst

@@ -24,8 +24,9 @@ is ``address(this).balance``.
     function to that contract like the one below, and call that function instead.
     function to that contract like the one below, and call that function instead.
 
 
 .. note::
 .. note::
-    On Solana, checking the balance of an account different than the data account
+    On Solana, checking the balance of an account different than the program account
     requires that it be passed as an AccountMeta during the transaction.
     requires that it be passed as an AccountMeta during the transaction.
+    It is not common practice for the program account to hold native Solana tokens.
 
 
 .. code-block:: solidity
 .. code-block:: solidity
 
 

+ 5 - 3
docs/targets/solana.rst

@@ -45,9 +45,11 @@ Runtime
 
 
 - The Solana target requires `Solana <https://www.solana.com/>`_ v1.8.1.
 - The Solana target requires `Solana <https://www.solana.com/>`_ v1.8.1.
 - Function selectors are eight bytes wide and known as *discriminators*.
 - Function selectors are eight bytes wide and known as *discriminators*.
-- Solana provides different builtins, e.g. ``tx.program_id`` and ``tx.accounts``.
-- When creating a contract in Solidity using ``new``, one :ref:`needs to provide <solana_constructor>` the data account
-  address that is going to be initialized for the new contract.
+- Solana provides different builtins, e.g. ``block.slot`` and ``tx.accounts``.
+- When calling an external function or instantiating a contract using ``new``, one
+  :ref:`needs to provide <solana_constructor>` the necessary accounts for the transaction.
+- The keyword ``this`` returns the contract's program account, also know as program id.
+
 
 
 Compute budget
 Compute budget
 ++++++++++++++
 ++++++++++++++

+ 1 - 1
integration/anchor/tests/anchor.ts

@@ -17,7 +17,7 @@ describe("Anchor", () => {
 
 
     const program = anchor.workspace.Anchor as Program<Anchor>;
     const program = anchor.workspace.Anchor as Program<Anchor>;
 
 
-    const [myAccount, bump] = await anchor.web3.PublicKey.findProgramAddress([seed], program.programId);
+    const [myAccount, bump] = anchor.web3.PublicKey.findProgramAddressSync([seed], program.programId);
 
 
 
 
     const { SystemProgram } = anchor.web3;
     const { SystemProgram } = anchor.web3;

+ 1 - 1
integration/polkadot/call_flags.sol

@@ -57,7 +57,7 @@ contract CallFlags {
     }
     }
 
 
     // Does this.call() on this instead of address.call()
     // Does this.call() on this instead of address.call()
-    function call_this(uint32 _x) public pure returns (uint32) {
+    function call_this(uint32 _x) public view returns (uint32) {
         return this.foo{flags: bitflags([CallFlag.ALLOW_REENTRY])}(_x);
         return this.foo{flags: bitflags([CallFlag.ALLOW_REENTRY])}(_x);
     }
     }
 }
 }

+ 1 - 1
integration/polkadot/issue666.sol

@@ -11,7 +11,7 @@ contract Inc {
 	_flipper = _flipperContract;
 	_flipper = _flipperContract;
     }
     }
 
 
-    function superFlip () pure public {
+    function superFlip () view public {
 	_flipper.flip();
 	_flipper.flip();
     }
     }
 }
 }

+ 0 - 2
integration/solana/balances.spec.ts

@@ -12,7 +12,6 @@ describe('Deploy solang contract and test', function () {
         let { program, storage, payer, provider } = await loadContractAndCallConstructor('balances', []);
         let { program, storage, payer, provider } = await loadContractAndCallConstructor('balances', []);
 
 
         let res = await program.methods.getBalance(payer.publicKey)
         let res = await program.methods.getBalance(payer.publicKey)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: payer.publicKey, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: payer.publicKey, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
@@ -38,7 +37,6 @@ describe('Deploy solang contract and test', function () {
         await sendAndConfirmTransaction(provider.connection, transaction, [payer]);
         await sendAndConfirmTransaction(provider.connection, transaction, [payer]);
 
 
         await program.methods.send(payer.publicKey, new BN(500))
         await program.methods.send(payer.publicKey, new BN(500))
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([
             .remainingAccounts([
                 { pubkey: storage.publicKey, isSigner: true, isWritable: true },
                 { pubkey: storage.publicKey, isSigner: true, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true }
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true }

+ 0 - 2
integration/solana/builtins.spec.ts

@@ -29,7 +29,6 @@ describe('Testing builtins', function () {
         expect(res['return1']).toEqual([0xfe]);
         expect(res['return1']).toEqual([0xfe]);
 
 
         res = await program.methods.mrNow()
         res = await program.methods.mrNow()
-            .accounts({ dataAccount: storage.publicKey })
             .view();
             .view();
 
 
         let now = Math.floor(+new Date() / 1000);
         let now = Math.floor(+new Date() / 1000);
@@ -40,7 +39,6 @@ describe('Testing builtins', function () {
         expect(ts).toBeGreaterThan(now - 120);
         expect(ts).toBeGreaterThan(now - 120);
 
 
         res = await program.methods.mrSlot()
         res = await program.methods.mrSlot()
-            .accounts({ dataAccount: storage.publicKey })
             .view();
             .view();
 
 
         let sol_slot = Number(res);
         let sol_slot = Number(res);

+ 21 - 30
integration/solana/calls.spec.ts

@@ -26,22 +26,16 @@ describe('Testing calls', function () {
 
 
         expect(res).toEqual(new BN(102));
         expect(res).toEqual(new BN(102));
 
 
-        let address_caller = caller.storage.publicKey;
-        let address_callee = callee.storage.publicKey;
-        let address_callee2 = callee2.storage.publicKey;
-
         res = await caller.program.methods.whoAmI()
         res = await caller.program.methods.whoAmI()
-            .accounts({ dataAccount: caller.storage.publicKey })
             .view();
             .view();
 
 
-        expect(res).toStrictEqual(address_caller);
+        expect(res).toStrictEqual(caller.program_key);
 
 
-        await caller.program.methods.doCall(address_callee, new BN(13123))
-            .accounts({ dataAccount: caller.storage.publicKey })
-            .remainingAccounts([
-                { pubkey: callee.storage.publicKey, isSigner: false, isWritable: true },
-                { pubkey: callee.program_key, isSigner: false, isWritable: false },
-            ])
+        await caller.program.methods.doCall(callee.program_key, new BN(13123))
+            .accounts({
+                callee_dataAccount: callee.storage.publicKey,
+                callee_programId: callee.program_key,
+                })
             .rpc();
             .rpc();
 
 
         res = await callee.program.methods.getX()
         res = await callee.program.methods.getX()
@@ -50,33 +44,30 @@ describe('Testing calls', function () {
 
 
         expect(res).toEqual(new BN(13123));
         expect(res).toEqual(new BN(13123));
 
 
-        res = await caller.program.methods.doCall2(address_callee, new BN(20000))
-            .accounts({ dataAccount: caller.storage.publicKey })
-            .remainingAccounts([
-                { pubkey: callee.storage.publicKey, isSigner: false, isWritable: true },
-                { pubkey: callee.program_key, isSigner: false, isWritable: false },
-                { pubkey: caller.program_key, isSigner: false, isWritable: false },
-            ])
+        res = await caller.program.methods.doCall2(callee.program_key, new BN(20000))
+            .accounts({
+                callee_dataAccount: callee.storage.publicKey,
+                callee_programId: callee.program_key,
+            })
             .view();
             .view();
 
 
         expect(res).toEqual(new BN(33123));
         expect(res).toEqual(new BN(33123));
 
 
-        let all_keys = [
-            { pubkey: callee.storage.publicKey, isSigner: false, isWritable: true },
-            { pubkey: callee.program_key, isSigner: false, isWritable: false },
-            { pubkey: callee2.storage.publicKey, isSigner: false, isWritable: true },
-            { pubkey: callee2.program_key, isSigner: false, isWritable: false },
-        ];
-
-        res = await caller.program.methods.doCall3(address_callee, address_callee2, [new BN(3), new BN(5), new BN(7), new BN(9)], "yo")
-            .remainingAccounts(all_keys)
+        res = await caller.program.methods.doCall3(callee.program_key, callee2.program_key, [new BN(3), new BN(5), new BN(7), new BN(9)], "yo")
+            .accounts({
+                callee2_programId: callee2.program_key,
+                callee_programId: callee.program_key,
+            })
             .view();
             .view();
 
 
         expect(res.return0).toEqual(new BN(24));
         expect(res.return0).toEqual(new BN(24));
         expect(res.return1).toBe("my name is callee");
         expect(res.return1).toBe("my name is callee");
 
 
-        res = await caller.program.methods.doCall4(address_callee, address_callee2, [new BN(1), new BN(2), new BN(3), new BN(4)], "asda")
-            .remainingAccounts(all_keys)
+        res = await caller.program.methods.doCall4(callee.program_key, callee2.program_key, [new BN(1), new BN(2), new BN(3), new BN(4)], "asda")
+            .accounts({
+                callee2_programId: callee2.program_key,
+                callee_programId: callee.program_key,
+            })
             .view();
             .view();
 
 
         expect(res.return0).toEqual(new BN(10));
         expect(res.return0).toEqual(new BN(10));

+ 10 - 11
integration/solana/create_contract.sol

@@ -4,25 +4,24 @@ contract creator {
     Child public c;
     Child public c;
     Child public c_metas;
     Child public c_metas;
 
 
-    function create_child(address child) external {
+    function create_child() external {
         print("Going to create child");
         print("Going to create child");
-        c = new Child{address: child}();
+        c = new Child();
 
 
         c.say_hello();
         c.say_hello();
     }
     }
 
 
-    function create_seed1(address child, bytes seed, bytes1 bump, uint64 space) external {
+    function create_seed1(bytes seed, bytes1 bump, uint64 space) external {
         print("Going to create Seed1");
         print("Going to create Seed1");
-        Seed1 s = new Seed1{address: child}(seed, bump, space);
+        Seed1 s = new Seed1(seed, bump, space);
 
 
         s.say_hello();
         s.say_hello();
     }
     }
 
 
-    function create_seed2(address child, bytes seed, uint32 space) external {
+    function create_seed2(bytes seed, uint32 space) external {
         print("Going to create Seed2");
         print("Going to create Seed2");
 
 
-        new Seed2{address: child}(seed, space);
-
+        new Seed2(seed, space);
     }
     }
 
 
     function create_child_with_metas(address child, address payer) public {
     function create_child_with_metas(address child, address payer) public {
@@ -37,8 +36,8 @@ contract creator {
         c_metas.use_metas();
         c_metas.use_metas();
     }
     }
 
 
-    function create_without_annotation(address child) external {
-        MyCreature cc = new MyCreature{address: child}();
+    function create_without_annotation() external {
+        MyCreature cc = new MyCreature();
         cc.say_my_name();
         cc.say_my_name();
     }
     }
 }
 }
@@ -88,9 +87,9 @@ contract Seed2 {
     }
     }
 
 
     function check() public view {
     function check() public view {
-        address pda = create_program_address([ "sunflower", my_seed ], tx.program_id);
+        address pda = create_program_address([ "sunflower", my_seed ], address(this));
 
 
-        if (pda == address(this)) {
+        if (pda == tx.accounts.dataAccount.key) {
             print("I am PDA.");
             print("I am PDA.");
         }
         }
     }
     }

+ 19 - 28
integration/solana/create_contract.spec.ts

@@ -22,15 +22,13 @@ describe('ChildContract', function () {
         let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
         let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
         let child = Keypair.generate();
         let child = Keypair.generate();
 
 
-        const signature = await program.methods.createChild(child.publicKey)
+        const signature = await program.methods.createChild()
             .accounts({
             .accounts({
                 dataAccount: storage.publicKey,
                 dataAccount: storage.publicKey,
+                Child_programId: child_program,
                 payer: payer.publicKey,
                 payer: payer.publicKey,
+                Child_dataAccount: child.publicKey,
             })
             })
-            .remainingAccounts([
-                { pubkey: child_program, isSigner: false, isWritable: false },
-                { pubkey: child.publicKey, isSigner: true, isWritable: true },
-            ])
             .signers([payer, child])
             .signers([payer, child])
             .rpc({ commitment: 'confirmed' });
             .rpc({ commitment: 'confirmed' });
 
 
@@ -51,15 +49,12 @@ describe('ChildContract', function () {
         let [address, bump] = await PublicKey.findProgramAddress([seed], seed_program);
         let [address, bump] = await PublicKey.findProgramAddress([seed], seed_program);
 
 
         const signature = await program.methods.createSeed1(
         const signature = await program.methods.createSeed1(
-            address, seed, Buffer.from([bump]), new BN(711))
+            seed, Buffer.from([bump]), new BN(711))
             .accounts({
             .accounts({
-                dataAccount: storage.publicKey,
+                Seed1_programId: seed_program,
                 payer: payer.publicKey,
                 payer: payer.publicKey,
+                Seed1_dataAccount: address,
             })
             })
-            .remainingAccounts([
-                { pubkey: seed_program, isSigner: false, isWritable: false },
-                { pubkey: address, isSigner: false, isWritable: true },
-            ])
             .signers([payer])
             .signers([payer])
             .rpc({ commitment: 'confirmed' });
             .rpc({ commitment: 'confirmed' });
 
 
@@ -84,15 +79,12 @@ describe('ChildContract', function () {
         let seed = Buffer.concat([bare_seed, Buffer.from([bump])]);
         let seed = Buffer.concat([bare_seed, Buffer.from([bump])]);
 
 
         const signature = await program.methods.createSeed2(
         const signature = await program.methods.createSeed2(
-            address, seed, new BN(9889))
+            seed, new BN(9889))
             .accounts({
             .accounts({
-                dataAccount: storage.publicKey,
-                payer: payer.publicKey
+                Seed2_programId: seed_program,
+                payer: payer.publicKey,
+                Seed2_dataAccount: address,
             })
             })
-            .remainingAccounts([
-                { pubkey: seed_program, isSigner: false, isWritable: false },
-                { pubkey: address, isSigner: false, isWritable: true },
-            ])
             .signers([payer])
             .signers([payer])
             .rpc({ commitment: 'confirmed' });
             .rpc({ commitment: 'confirmed' });
 
 
@@ -122,9 +114,11 @@ describe('ChildContract', function () {
         let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
         let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
 
 
         const signature = await program.methods.createChildWithMetas(child.publicKey, payer.publicKey)
         const signature = await program.methods.createChildWithMetas(child.publicKey, payer.publicKey)
-            .accounts({ dataAccount: storage.publicKey })
+            .accounts({
+                dataAccount: storage.publicKey,
+                Child_programId: child_program,
+            })
             .remainingAccounts([
             .remainingAccounts([
-                { pubkey: child_program, isSigner: false, isWritable: false },
                 { pubkey: child.publicKey, isSigner: true, isWritable: true },
                 { pubkey: child.publicKey, isSigner: true, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: true, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: true, isWritable: true },
             ])
             ])
@@ -146,14 +140,11 @@ describe('ChildContract', function () {
         const child_program = new PublicKey("8gTkAidfM82u3DGbKcZpHwL5p47KQA16MDb4WmrHdmF6");
         const child_program = new PublicKey("8gTkAidfM82u3DGbKcZpHwL5p47KQA16MDb4WmrHdmF6");
 
 
         await create_account(child, child_program, 8192);
         await create_account(child, child_program, 8192);
-        const signature = await program.methods.createWithoutAnnotation(child.publicKey)
-            .accounts({ dataAccount: storage.publicKey })
-            .remainingAccounts(
-                [
-                    { pubkey: child_program, isSigner: false, isWritable: false },
-                    { pubkey: child.publicKey, isSigner: true, isWritable: true }
-                ]
-            ).signers([child])
+        const signature = await program.methods.createWithoutAnnotation()
+            .accounts({
+                MyCreature_dataAccount: child.publicKey,
+                MyCreature_programId: child_program,
+            })
             .rpc({ commitment: 'confirmed' });
             .rpc({ commitment: 'confirmed' });
 
 
         const tx = await provider.connection.getTransaction(signature, {
         const tx = await provider.connection.getTransaction(signature, {

+ 0 - 1
integration/solana/events.spec.ts

@@ -10,7 +10,6 @@ describe('Test events', function () {
         const { program, storage } = await loadContractAndCallConstructor('MyContractEvents');
         const { program, storage } = await loadContractAndCallConstructor('MyContractEvents');
 
 
         const res = await program.methods.test()
         const res = await program.methods.test()
-            .accounts({ dataAccount: storage.publicKey })
             .simulate();
             .simulate();
 
 
         const event1 = res.events[0];
         const event1 = res.events[0];

+ 9 - 9
integration/solana/runtime_errors.spec.ts

@@ -48,7 +48,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.invalidInstruction().accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.invalidInstruction().simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: reached invalid instruction in runtime_errors.sol:101:13-22,
             expect(logs).toContain(`Program log: runtime_error: reached invalid instruction in runtime_errors.sol:101:13-22,
@@ -57,7 +57,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.byteCastFailure(new BN(33)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.byteCastFailure(new BN(33)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: bytes cast error in runtime_errors.sol:107:23-40,
             expect(logs).toContain(`Program log: runtime_error: bytes cast error in runtime_errors.sol:107:23-40,
@@ -66,7 +66,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.iWillRevert().accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.iWillRevert().simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: revert encountered in runtime_errors.sol:69:9-17,
             expect(logs).toContain(`Program log: runtime_error: revert encountered in runtime_errors.sol:69:9-17,
@@ -74,7 +74,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.assertTest(new BN(9)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.assertTest(new BN(9)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: assert failure in runtime_errors.sol:34:16-24,
             expect(logs).toContain(`Program log: runtime_error: assert failure in runtime_errors.sol:34:16-24,
@@ -82,7 +82,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.writeIntegerFailure(new BN(1)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.writeIntegerFailure(new BN(1)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: integer too large to write in buffer in runtime_errors.sol:74:18-31,
             expect(logs).toContain(`Program log: runtime_error: integer too large to write in buffer in runtime_errors.sol:74:18-31,
@@ -90,7 +90,7 @@ describe('Runtime Errors', function () {
         }
         }
 
 
         try {
         try {
-            let res = await program.methods.writeBytesFailure(new BN(9)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.writeBytesFailure(new BN(9)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: data does not fit into buffer in runtime_errors.sol:80:18-28,
             expect(logs).toContain(`Program log: runtime_error: data does not fit into buffer in runtime_errors.sol:80:18-28,
@@ -99,7 +99,7 @@ describe('Runtime Errors', function () {
 
 
 
 
         try {
         try {
-            let res = await program.methods.readIntegerFailure(new BN(2)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.readIntegerFailure(new BN(2)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: read integer out of bounds in runtime_errors.sol:85:18-30,
             expect(logs).toContain(`Program log: runtime_error: read integer out of bounds in runtime_errors.sol:85:18-30,
@@ -108,7 +108,7 @@ describe('Runtime Errors', function () {
 
 
 
 
         try {
         try {
-            let res = await program.methods.outOfBounds(new BN(19)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.outOfBounds(new BN(19)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: array index out of bounds in runtime_errors.sol:96:16-21,
             expect(logs).toContain(`Program log: runtime_error: array index out of bounds in runtime_errors.sol:96:16-21,
@@ -117,7 +117,7 @@ describe('Runtime Errors', function () {
 
 
 
 
         try {
         try {
-            let res = await program.methods.truncFailure(new BN(99999999999999)).accounts({ dataAccount: storage.publicKey }).simulate();
+            let res = await program.methods.truncFailure(new BN(99999999999999)).simulate();
         } catch (e: any) {
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
             const logs = e.simulationResponse.logs;
             expect(logs).toContain(`Program log: runtime_error: truncated type overflows in runtime_errors.sol:90:37-42,
             expect(logs).toContain(`Program log: runtime_error: truncated type overflows in runtime_errors.sol:90:37-42,

+ 42 - 42
integration/solana/simple.spec.ts

@@ -29,121 +29,121 @@ describe('Simple solang tests', function () {
         // TEST Basic enums
         // TEST Basic enums
         // in ethereum, an enum is described as an uint8 so can't use the enum
         // in ethereum, an enum is described as an uint8 so can't use the enum
         // names programmatically. 0 = add, 1 = sub, 2 = mul, 3 = div, 4 = mod, 5 = pow, 6 = shl, 7 = shr
         // names programmatically. 0 = add, 1 = sub, 2 = mul, 3 = div, 4 = mod, 5 = pow, 6 = shl, 7 = shr
-        let res = await program.methods.isMul({ mul: {} }).accounts({ dataAccount: storage.publicKey }).view();
+        let res = await program.methods.isMul({ mul: {} }).view();
         expect(res).toBe(true);
         expect(res).toBe(true);
 
 
-        res = await program.methods.returnDiv().accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.returnDiv().view();
         expect(res.div).toBeDefined();
         expect(res.div).toBeDefined();
 
 
         // TEST uint and int types, and arithmetic/bitwise ops
         // TEST uint and int types, and arithmetic/bitwise ops
         res = await program.methods.opI64({ add: {} }, new BN(1000), new BN(4100)).view();
         res = await program.methods.opI64({ add: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(5100);
         expect(Number(res)).toBe(5100);
-        res = await program.methods.opI64({ sub: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ sub: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toStrictEqual(-3100);
         expect(Number(res)).toStrictEqual(-3100);
-        res = await program.methods.opI64({ mul: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ mul: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(4100000);
         expect(Number(res)).toBe(4100000);
-        res = await program.methods.opI64({ div: {} }, new BN(1000), new BN(10)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ div: {} }, new BN(1000), new BN(10)).view();
         expect(Number(res)).toBe(100);
         expect(Number(res)).toBe(100);
-        res = await program.methods.opI64({ mod: {} }, new BN(1000), new BN(99)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ mod: {} }, new BN(1000), new BN(99)).view();
         expect(Number(res)).toBe(10);
         expect(Number(res)).toBe(10);
-        res = await program.methods.opI64({ shl: {} }, new BN(-1000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ shl: {} }, new BN(-1000), new BN(8)).view();
         expect(Number(res)).toBe(-256000);
         expect(Number(res)).toBe(-256000);
-        res = await program.methods.opI64({ shr: {} }, new BN(-1000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ shr: {} }, new BN(-1000), new BN(8)).view();
         expect(Number(res)).toBe(-4);
         expect(Number(res)).toBe(-4);
 
 
-        res = await program.methods.opU64({ add: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ add: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(5100);
         expect(Number(res)).toBe(5100);
-        res = await program.methods.opU64({ sub: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ sub: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(18446744073709548516); // (2^64)-18446744073709548516 = 3100
         expect(Number(res)).toBe(18446744073709548516); // (2^64)-18446744073709548516 = 3100
-        res = await program.methods.opU64({ mul: {} }, new BN(123456789), new BN(123456789)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ mul: {} }, new BN(123456789), new BN(123456789)).view();
         expect(Number(res)).toBe(15241578750190521);
         expect(Number(res)).toBe(15241578750190521);
-        res = await program.methods.opU64({ div: {} }, new BN(123456789), new BN(100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ div: {} }, new BN(123456789), new BN(100)).view();
         expect(Number(res)).toBe(1234567);
         expect(Number(res)).toBe(1234567);
-        res = await program.methods.opU64({ mod: {} }, new BN(123456789), new BN(100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ mod: {} }, new BN(123456789), new BN(100)).view();
         expect(Number(res)).toBe(89);
         expect(Number(res)).toBe(89);
-        res = await program.methods.opU64({ pow: {} }, new BN(3), new BN(7)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU64({ pow: {} }, new BN(3), new BN(7)).view();
         expect(Number(res)).toBe(2187);
         expect(Number(res)).toBe(2187);
-        res = await program.methods.opI64({ shl: {} }, new BN(1000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ shl: {} }, new BN(1000), new BN(8)).view();
         expect(Number(res)).toBe(256000);
         expect(Number(res)).toBe(256000);
-        res = await program.methods.opI64({ shr: {} }, new BN(1000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI64({ shr: {} }, new BN(1000), new BN(8)).view();
         expect(Number(res)).toBe(3);
         expect(Number(res)).toBe(3);
 
 
         // now for 256 bit operations
         // now for 256 bit operations
-        res = await program.methods.opI256({ add: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ add: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(5100);
         expect(Number(res)).toBe(5100);
-        res = await program.methods.opI256({ sub: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ sub: {} }, new BN(1000), new BN(4100)).view();
         expect(res).toStrictEqual(new BN(-3100));
         expect(res).toStrictEqual(new BN(-3100));
-        res = await program.methods.opI256({ mul: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ mul: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(4100000);
         expect(Number(res)).toBe(4100000);
-        res = await program.methods.opI256({ div: {} }, new BN(1000), new BN(10)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ div: {} }, new BN(1000), new BN(10)).view();
         expect(Number(res)).toBe(100);
         expect(Number(res)).toBe(100);
-        res = await program.methods.opI256({ mod: {} }, new BN(1000), new BN(99)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ mod: {} }, new BN(1000), new BN(99)).view();
         expect(Number(res)).toBe(10);
         expect(Number(res)).toBe(10);
-        res = await program.methods.opI256({ shl: {} }, new BN(-10000000000000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ shl: {} }, new BN(-10000000000000), new BN(8)).view();
         expect(Number(res)).toBe(-2560000000000000);
         expect(Number(res)).toBe(-2560000000000000);
-        res = await program.methods.opI256({ shr: {} }, new BN(-10000000000000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opI256({ shr: {} }, new BN(-10000000000000), new BN(8)).view();
         expect(Number(res)).toBe(-39062500000);
         expect(Number(res)).toBe(-39062500000);
 
 
-        res = await program.methods.opU256({ add: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ add: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(5100);
         expect(Number(res)).toBe(5100);
-        res = await program.methods.opU256({ sub: {} }, new BN(1000), new BN(4100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ sub: {} }, new BN(1000), new BN(4100)).view();
         expect(Number(res)).toBe(115792089237316195423570985008687907853269984665640564039457584007913129636836); // (2^64)-18446744073709548516 = 3100
         expect(Number(res)).toBe(115792089237316195423570985008687907853269984665640564039457584007913129636836); // (2^64)-18446744073709548516 = 3100
-        res = await program.methods.opU256({ mul: {} }, new BN(123456789), new BN(123456789)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ mul: {} }, new BN(123456789), new BN(123456789)).view();
         expect(Number(res)).toBe(15241578750190521);
         expect(Number(res)).toBe(15241578750190521);
-        res = await program.methods.opU256({ div: {} }, new BN(123456789), new BN(100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ div: {} }, new BN(123456789), new BN(100)).view();
         expect(Number(res)).toBe(1234567);
         expect(Number(res)).toBe(1234567);
-        res = await program.methods.opU256({ mod: {} }, new BN(123456789), new BN(100)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ mod: {} }, new BN(123456789), new BN(100)).view();
         expect(Number(res)).toBe(89);
         expect(Number(res)).toBe(89);
-        res = await program.methods.opU256({ pow: {} }, new BN(123456789), new BN(9)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ pow: {} }, new BN(123456789), new BN(9)).view();
         expect(Number(res)).toBe(6662462759719942007440037531362779472290810125440036903063319585255179509);
         expect(Number(res)).toBe(6662462759719942007440037531362779472290810125440036903063319585255179509);
-        res = await program.methods.opU256({ shl: {} }, new BN(10000000000000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ shl: {} }, new BN(10000000000000), new BN(8)).view();
         expect(Number(res)).toBe(2560000000000000);
         expect(Number(res)).toBe(2560000000000000);
-        res = await program.methods.opU256({ shr: {} }, new BN(10000000000000), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU256({ shr: {} }, new BN(10000000000000), new BN(8)).view();
         expect(Number(res)).toBe(39062500000);
         expect(Number(res)).toBe(39062500000);
 
 
         // TEST bytesN
         // TEST bytesN
-        res = await program.methods.returnU86().accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.returnU86().view();
         expect(res).toStrictEqual([0x41, 0x42, 0x43, 0x44, 0x45, 0x46]);
         expect(res).toStrictEqual([0x41, 0x42, 0x43, 0x44, 0x45, 0x46]);
 
 
         // TEST bytes5
         // TEST bytes5
         res = await program.methods.opU85Shift({ shl: {} },
         res = await program.methods.opU85Shift({ shl: {} },
-            Buffer.from("deadcafe59", "hex"), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("deadcafe59", "hex"), new BN(8)).view();
         expect(res).toStrictEqual([0xad, 0xca, 0xfe, 0x59, 0x00]);
         expect(res).toStrictEqual([0xad, 0xca, 0xfe, 0x59, 0x00]);
-        res = await program.methods.opU85Shift({ shr: {} }, Buffer.from("deadcafe59", "hex"), new BN(8)).accounts({ dataAccount: storage.publicKey }).view();
+        res = await program.methods.opU85Shift({ shr: {} }, Buffer.from("deadcafe59", "hex"), new BN(8)).view();
         expect(res).toStrictEqual([0x00, 0xde, 0xad, 0xca, 0xfe]);
         expect(res).toStrictEqual([0x00, 0xde, 0xad, 0xca, 0xfe]);
         res = await program.methods.opU85({ or: {} },
         res = await program.methods.opU85({ or: {} },
             Buffer.from("deadcafe59", "hex"),
             Buffer.from("deadcafe59", "hex"),
-            Buffer.from("0000000006", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("0000000006", "hex")).view();
         expect(res).toStrictEqual([0xde, 0xad, 0xca, 0xfe, 0x5f]);
         expect(res).toStrictEqual([0xde, 0xad, 0xca, 0xfe, 0x5f]);
         res = await program.methods.opU85({ and: {} },
         res = await program.methods.opU85({ and: {} },
             Buffer.from("deadcafe59", "hex"),
             Buffer.from("deadcafe59", "hex"),
-            Buffer.from("00000000ff", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("00000000ff", "hex")).view();
         expect(res).toStrictEqual([0x00, 0x00, 0x00, 0x00, 0x59]);
         expect(res).toStrictEqual([0x00, 0x00, 0x00, 0x00, 0x59]);
         res = await program.methods.opU85({ xor: {} },
         res = await program.methods.opU85({ xor: {} },
             Buffer.from("deadcafe59", "hex"),
             Buffer.from("deadcafe59", "hex"),
-            Buffer.from("00000000ff", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("00000000ff", "hex")).view();
         expect(res).toStrictEqual([0xde, 0xad, 0xca, 0xfe, 0xa6]);
         expect(res).toStrictEqual([0xde, 0xad, 0xca, 0xfe, 0xa6]);
 
 
         // TEST bytes14
         // TEST bytes14
         res = await program.methods.opU814Shift({ shl: {} },
         res = await program.methods.opU814Shift({ shl: {} },
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"), new BN(9))
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"), new BN(9))
-            .accounts({ dataAccount: storage.publicKey }).view();
+            .view();
         expect(res).toStrictEqual([0x5b, 0x95, 0xfc, 0x24, 0x68, 0xac, 0xf1, 0x35, 0x79, 0xbd, 0xf7, 0xdd, 0xee, 0x00]);
         expect(res).toStrictEqual([0x5b, 0x95, 0xfc, 0x24, 0x68, 0xac, 0xf1, 0x35, 0x79, 0xbd, 0xf7, 0xdd, 0xee, 0x00]);
         res = await program.methods.opU814Shift({ shr: {} },
         res = await program.methods.opU814Shift({ shr: {} },
-            Buffer.from("deadcafe123456789abcdefbeef7", "hex"), new BN(9)).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("deadcafe123456789abcdefbeef7", "hex"), new BN(9)).view();
         expect(res).toStrictEqual([0x00, 0x6f, 0x56, 0xe5, 0x7f, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, 0x7d, 0xf7]);
         expect(res).toStrictEqual([0x00, 0x6f, 0x56, 0xe5, 0x7f, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, 0x7d, 0xf7]);
         res = await program.methods.opU814({ or: {} },
         res = await program.methods.opU814({ or: {} },
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
-            Buffer.from("0000060000000000000000000000", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("0000060000000000000000000000", "hex")).view();
         expect(res).toStrictEqual([0xde, 0xad, 0xce, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfb, 0xee, 0xf7]);
         expect(res).toStrictEqual([0xde, 0xad, 0xce, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfb, 0xee, 0xf7]);
         res = await program.methods.opU814({ and: {} },
         res = await program.methods.opU814({ and: {} },
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
-            Buffer.from("000000000000000000ff00000000", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("000000000000000000ff00000000", "hex")).view();
         expect(res).toStrictEqual(
         expect(res).toStrictEqual(
             [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00]);
             [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00]);
         res = await program.methods.opU814({ xor: {} },
         res = await program.methods.opU814({ xor: {} },
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
             Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
-            Buffer.from("ff00000000000000000000000000", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+            Buffer.from("ff00000000000000000000000000", "hex")).view();
         expect(res).toStrictEqual(
         expect(res).toStrictEqual(
             [0x21, 0xad, 0xca, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfb, 0xee, 0xf7]);
             [0x21, 0xad, 0xca, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfb, 0xee, 0xf7]);
 
 

+ 0 - 1
integration/solana/simple_collectible.spec.ts

@@ -72,7 +72,6 @@ describe('Simple collectible', function () {
         await program.methods.transferOwnership(
         await program.methods.transferOwnership(
             owner_token_account.address,
             owner_token_account.address,
             new_owner_token_account.address)
             new_owner_token_account.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([
             .remainingAccounts([
                 { pubkey: new_owner_token_account.address, isSigner: false, isWritable: true },
                 { pubkey: new_owner_token_account.address, isSigner: false, isWritable: true },
                 { pubkey: owner_token_account.address, isSigner: false, isWritable: true },
                 { pubkey: owner_token_account.address, isSigner: false, isWritable: true },

+ 0 - 13
integration/solana/system_instruction.spec.ts

@@ -28,7 +28,6 @@ describe('Test system instructions', function () {
                 { pubkey: payer.publicKey, isSigner: true, isWritable: false },
                 { pubkey: payer.publicKey, isSigner: true, isWritable: false },
                 { pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
                 { pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, to_key_pair]).rpc();
             .signers([payer, to_key_pair]).rpc();
     });
     });
 
 
@@ -51,7 +50,6 @@ describe('Test system instructions', function () {
                 { pubkey: to_key_pair, isSigner: false, isWritable: true },
                 { pubkey: to_key_pair, isSigner: false, isWritable: true },
                 { pubkey: base_keypair.publicKey, isSigner: true, isWritable: false },
                 { pubkey: base_keypair.publicKey, isSigner: true, isWritable: false },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, base_keypair]).rpc();
             .signers([payer, base_keypair]).rpc();
     });
     });
 
 
@@ -67,7 +65,6 @@ describe('Test system instructions', function () {
                 { pubkey: payer.publicKey, isSigner: false, isWritable: false },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: false },
                 { pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
                 { pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, to_key_pair]).rpc();
             .signers([payer, to_key_pair]).rpc();
     });
     });
 
 
@@ -86,7 +83,6 @@ describe('Test system instructions', function () {
                 { pubkey: payer.publicKey, isSigner: false, isWritable: false },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: false },
                 { pubkey: to_key_pair, isSigner: false, isWritable: true },
                 { pubkey: to_key_pair, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer]).rpc();
             .signers([payer]).rpc();
     });
     });
 
 
@@ -102,7 +98,6 @@ describe('Test system instructions', function () {
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
                 { pubkey: dest.publicKey, isSigner: false, isWritable: true },
                 { pubkey: dest.publicKey, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer]).rpc();
             .signers([payer]).rpc();
     });
     });
 
 
@@ -128,7 +123,6 @@ describe('Test system instructions', function () {
                 { pubkey: dest.publicKey, isSigner: false, isWritable: true },
                 { pubkey: dest.publicKey, isSigner: false, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: true, isWritable: false },
                 { pubkey: payer.publicKey, isSigner: true, isWritable: false },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer]).rpc();
             .signers([payer]).rpc();
     });
     });
 
 
@@ -142,7 +136,6 @@ describe('Test system instructions', function () {
             .remainingAccounts([
             .remainingAccounts([
                 { pubkey: account.publicKey, isSigner: true, isWritable: true },
                 { pubkey: account.publicKey, isSigner: true, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, account]).rpc();
             .signers([payer, account]).rpc();
     });
     });
 
 
@@ -163,7 +156,6 @@ describe('Test system instructions', function () {
                 { pubkey: account.publicKey, isSigner: true, isWritable: false },
                 { pubkey: account.publicKey, isSigner: true, isWritable: false },
                 { pubkey: derived_key, isSigner: false, isWritable: true },
                 { pubkey: derived_key, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, account]).rpc();
             .signers([payer, account]).rpc();
     });
     });
 
 
@@ -187,7 +179,6 @@ describe('Test system instructions', function () {
                 { pubkey: derived_account, isSigner: false, isWritable: true },
                 { pubkey: derived_account, isSigner: false, isWritable: true },
                 { pubkey: base_address.publicKey, isSigner: true, isWritable: true },
                 { pubkey: base_address.publicKey, isSigner: true, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, base_address]).rpc();
             .signers([payer, base_address]).rpc();
     });
     });
 
 
@@ -207,7 +198,6 @@ describe('Test system instructions', function () {
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
                 { pubkey: nonce.publicKey, isSigner: true, isWritable: true },
                 { pubkey: nonce.publicKey, isSigner: true, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([payer, nonce]).rpc();
             .signers([payer, nonce]).rpc();
 
 
         await program.methods.advanceNonceAccount(
         await program.methods.advanceNonceAccount(
@@ -218,7 +208,6 @@ describe('Test system instructions', function () {
                 { pubkey: authority.publicKey, isSigner: true, isWritable: false },
                 { pubkey: authority.publicKey, isSigner: true, isWritable: false },
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([authority]).rpc();
             .signers([authority]).rpc();
 
 
         await program.methods.withdrawNonceAccount(
         await program.methods.withdrawNonceAccount(
@@ -233,7 +222,6 @@ describe('Test system instructions', function () {
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
                 { pubkey: payer.publicKey, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([authority]).rpc();
             .signers([authority]).rpc();
 
 
         const new_authority = Keypair.generate();
         const new_authority = Keypair.generate();
@@ -246,7 +234,6 @@ describe('Test system instructions', function () {
                 { pubkey: authority.publicKey, isSigner: true, isWritable: false },
                 { pubkey: authority.publicKey, isSigner: true, isWritable: false },
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
                 { pubkey: nonce.publicKey, isSigner: false, isWritable: true },
             ])
             ])
-            .accounts({ dataAccount: storage.publicKey })
             .signers([authority]).rpc();
             .signers([authority]).rpc();
     });
     });
 });
 });

+ 0 - 9
integration/solana/token.spec.ts

@@ -32,7 +32,6 @@ describe('Create spl-token and use from solidity', function () {
             .accounts({ dataAccount: storage.publicKey })
             .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: mint, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: mint, isSigner: false, isWritable: false }])
             .view();
             .view();
-
         expect(total_supply.toNumber()).toBe(0);
         expect(total_supply.toNumber()).toBe(0);
 
 
         const tokenAccount = await getOrCreateAssociatedTokenAccount(
         const tokenAccount = await getOrCreateAssociatedTokenAccount(
@@ -43,7 +42,6 @@ describe('Create spl-token and use from solidity', function () {
         )
         )
 
 
         let balance = await program.methods.getBalance(tokenAccount.address)
         let balance = await program.methods.getBalance(tokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
@@ -71,7 +69,6 @@ describe('Create spl-token and use from solidity', function () {
 
 
         expect(total_supply.toNumber()).toBe(100000);
         expect(total_supply.toNumber()).toBe(100000);
         balance = await program.methods.getBalance(tokenAccount.address)
         balance = await program.methods.getBalance(tokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
@@ -92,7 +89,6 @@ describe('Create spl-token and use from solidity', function () {
             otherTokenAccount.address,
             otherTokenAccount.address,
             payer.publicKey,
             payer.publicKey,
             new BN(70000))
             new BN(70000))
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([
             .remainingAccounts([
                 { pubkey: otherTokenAccount.address, isSigner: false, isWritable: true },
                 { pubkey: otherTokenAccount.address, isSigner: false, isWritable: true },
                 { pubkey: tokenAccount.address, isSigner: false, isWritable: true },
                 { pubkey: tokenAccount.address, isSigner: false, isWritable: true },
@@ -108,14 +104,12 @@ describe('Create spl-token and use from solidity', function () {
 
 
         expect(total_supply.toNumber()).toBe(100000);
         expect(total_supply.toNumber()).toBe(100000);
         balance = await program.methods.getBalance(tokenAccount.address)
         balance = await program.methods.getBalance(tokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
         expect(balance.toNumber()).toBe(30000);
         expect(balance.toNumber()).toBe(30000);
 
 
         balance = await program.methods.getBalance(otherTokenAccount.address)
         balance = await program.methods.getBalance(otherTokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
@@ -135,7 +129,6 @@ describe('Create spl-token and use from solidity', function () {
             .signers([theOutsider])
             .signers([theOutsider])
             .rpc();
             .rpc();
 
 
-
         total_supply = await program.methods.totalSupply()
         total_supply = await program.methods.totalSupply()
             .accounts({ dataAccount: storage.publicKey })
             .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: mint, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: mint, isSigner: false, isWritable: false }])
@@ -143,14 +136,12 @@ describe('Create spl-token and use from solidity', function () {
 
 
         expect(total_supply.toNumber()).toBe(80000);
         expect(total_supply.toNumber()).toBe(80000);
         balance = await program.methods.getBalance(tokenAccount.address)
         balance = await program.methods.getBalance(tokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 
         expect(balance.toNumber()).toBe(30000);
         expect(balance.toNumber()).toBe(30000);
 
 
         balance = await program.methods.getBalance(otherTokenAccount.address)
         balance = await program.methods.getBalance(otherTokenAccount.address)
-            .accounts({ dataAccount: storage.publicKey })
             .remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
             .remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
             .view();
             .view();
 
 

+ 0 - 2
integration/solana/verify_sig.spec.ts

@@ -31,7 +31,6 @@ describe('Signature Check', function () {
         const result = await program.methods.verify(payer.publicKey, message, Buffer.from(signature))
         const result = await program.methods.verify(payer.publicKey, message, Buffer.from(signature))
             .preInstructions([instr1])
             .preInstructions([instr1])
             .accounts({
             .accounts({
-                dataAccount: storage.publicKey,
                 SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
                 SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
             })
             })
             .view();
             .view();
@@ -57,7 +56,6 @@ describe('Signature Check', function () {
         const result = await program.methods.verify(payer.publicKey, message, Buffer.from(broken_signature))
         const result = await program.methods.verify(payer.publicKey, message, Buffer.from(broken_signature))
             .preInstructions([instr1])
             .preInstructions([instr1])
             .accounts({
             .accounts({
-                dataAccount: storage.publicKey,
                 SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
                 SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
             })
             })
             .view();
             .view();

+ 149 - 503
src/abi/tests.rs

@@ -190,15 +190,7 @@ fn instructions_and_types() {
     assert!(idl.instructions[0].docs.is_none());
     assert!(idl.instructions[0].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].returns.is_none());
     assert!(idl.instructions[0].returns.is_none());
@@ -208,15 +200,7 @@ fn instructions_and_types() {
     assert!(idl.instructions[1].docs.is_none());
     assert!(idl.instructions[1].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: false,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", false, false)]
     );
     );
     assert!(idl.instructions[1].args.is_empty());
     assert!(idl.instructions[1].args.is_empty());
     assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
     assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
@@ -226,15 +210,7 @@ fn instructions_and_types() {
     assert!(idl.instructions[2].docs.is_none());
     assert!(idl.instructions[2].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[2].accounts,
         idl.instructions[2].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: false,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", false, false)]
     );
     );
     assert_eq!(
     assert_eq!(
         idl.instructions[2].args,
         idl.instructions[2].args,
@@ -274,15 +250,7 @@ fn instructions_and_types() {
     );
     );
     assert_eq!(
     assert_eq!(
         idl.instructions[4].accounts,
         idl.instructions[4].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
     assert_eq!(
     assert_eq!(
         idl.instructions[4].args,
         idl.instructions[4].args,
@@ -301,15 +269,7 @@ fn instructions_and_types() {
     );
     );
     assert_eq!(
     assert_eq!(
         idl.instructions[5].accounts,
         idl.instructions[5].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: false,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", false, false)]
     );
     );
     assert!(idl.instructions[5].args.is_empty());
     assert!(idl.instructions[5].args.is_empty());
     assert_eq!(idl.instructions[5].returns, Some(IdlType::String));
     assert_eq!(idl.instructions[5].returns, Some(IdlType::String));
@@ -318,15 +278,7 @@ fn instructions_and_types() {
     assert!(idl.instructions[6].docs.is_none());
     assert!(idl.instructions[6].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[6].accounts,
         idl.instructions[6].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", true, false),]
     );
     );
     assert!(idl.instructions[6].args.is_empty());
     assert!(idl.instructions[6].args.is_empty());
     assert_eq!(
     assert_eq!(
@@ -397,33 +349,14 @@ contract caller {
     assert!(idl.instructions[0].docs.is_none());
     assert!(idl.instructions[0].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].returns.is_none());
     assert!(idl.instructions[0].returns.is_none());
 
 
     assert_eq!(idl.instructions[1].name, "emitAll");
     assert_eq!(idl.instructions[1].name, "emitAll");
     assert!(idl.instructions[1].docs.is_none());
     assert!(idl.instructions[1].docs.is_none());
-    assert_eq!(
-        idl.instructions[1].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
-    );
+    assert!(idl.instructions[1].accounts.is_empty());
     assert_eq!(
     assert_eq!(
         idl.instructions[1].args,
         idl.instructions[1].args,
         vec![
         vec![
@@ -552,32 +485,13 @@ fn types() {
     assert!(idl.instructions[0].docs.is_none());
     assert!(idl.instructions[0].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].returns.is_none());
     assert!(idl.instructions[0].returns.is_none());
 
 
     assert_eq!(idl.instructions[1].name, "myFunc");
     assert_eq!(idl.instructions[1].name, "myFunc");
-    assert_eq!(
-        idl.instructions[1].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
-    );
+    assert!(idl.instructions[1].accounts.is_empty());
     assert_eq!(
     assert_eq!(
         idl.instructions[1].args,
         idl.instructions[1].args,
         vec![
         vec![
@@ -655,15 +569,7 @@ fn constructor() {
     assert!(idl.instructions[0].docs.is_none());
     assert!(idl.instructions[0].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
     assert_eq!(
     assert_eq!(
         idl.instructions[0].args,
         idl.instructions[0].args,
@@ -679,15 +585,7 @@ fn constructor() {
     assert!(idl.instructions[1].docs.is_none());
     assert!(idl.instructions[1].docs.is_none());
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: false,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", false, false)]
     );
     );
     assert!(idl.instructions[1].args.is_empty());
     assert!(idl.instructions[1].args.is_empty());
     assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
     assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
@@ -720,15 +618,7 @@ contract Testing {
     assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].args.is_empty());
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
 
 
     assert_eq!(idl.instructions[1].name, "getNum");
     assert_eq!(idl.instructions[1].name, "getNum");
@@ -1519,7 +1409,7 @@ fn data_account_signer() {
     contract caller {
     contract caller {
         // signer required
         // signer required
         @payer(wallet)
         @payer(wallet)
-        constructor(address wallet) {}
+        constructor() {}
     }"#;
     }"#;
 
 
     let mut ns = generate_namespace(src);
     let mut ns = generate_namespace(src);
@@ -1534,36 +1424,12 @@ fn data_account_signer() {
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "wallet".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            })
+            idl_account("dataAccount", true, true),
+            idl_account("wallet", true, true),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
-    assert!(idl.instructions[0].args.len() == 1);
+    assert!(idl.instructions[0].args.is_empty());
     assert!(idl.instructions[0].returns.is_none());
     assert!(idl.instructions[0].returns.is_none());
 
 
     let src = r#"
     let src = r#"
@@ -1585,33 +1451,9 @@ fn data_account_signer() {
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "wallet".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            })
+            idl_account("dataAccount", true, false),
+            idl_account("wallet", true, true),
+            idl_account("systemProgram", false, false)
         ]
         ]
     );
     );
     assert!(idl.instructions[0].args.len() == 1);
     assert!(idl.instructions[0].args.len() == 1);
@@ -1642,40 +1484,13 @@ fn accounts_call_chain() {
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
 
 
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
-        vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "clock".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
-        ]
+        vec![idl_account("clock", false, false)]
     );
     );
 
 
     assert_eq!(idl.instructions[2].name, "call_2");
     assert_eq!(idl.instructions[2].name, "call_2");
@@ -1723,48 +1538,16 @@ fn accounts_on_recursion() {
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        })]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
 
 
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "SysvarInstruction".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "clock".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("dataAccount", false, false),
+            idl_account("SysvarInstruction", false, false),
+            idl_account("clock", false, false),
         ]
         ]
     );
     );
 
 
@@ -1814,33 +1597,9 @@ fn system_account_for_payer_annotation() {
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "addr_".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("dataAccount", true, true),
+            idl_account("addr_", true, true),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
 }
 }
@@ -1884,26 +1643,7 @@ contract Test {
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
-        vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
-        ]
+        vec![idl_account("systemProgram", false, false)]
     );
     );
 }
 }
 
 
@@ -1946,33 +1686,8 @@ contract Test {
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "tokenProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("tokenProgram", false, false),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
 }
 }
@@ -2037,48 +1752,15 @@ contract Test {
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(idl.instructions[0].name, "new");
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
-        vec![IdlAccountItem::IdlAccount(IdlAccount {
-            name: "dataAccount".to_string(),
-            is_mut: true,
-            is_signer: false,
-            is_optional: Some(false),
-            docs: None,
-            pda: None,
-            relations: vec![],
-        }),]
+        vec![idl_account("dataAccount", true, false)]
     );
     );
 
 
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(idl.instructions[1].name, "call_1");
     assert_eq!(
     assert_eq!(
         idl.instructions[1].accounts,
         idl.instructions[1].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "rent".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("rent", false, false),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
 
 
@@ -2086,33 +1768,8 @@ contract Test {
     assert_eq!(
     assert_eq!(
         idl.instructions[2].accounts,
         idl.instructions[2].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "associatedTokenProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("associatedTokenProgram", false, false),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
 
 
@@ -2120,33 +1777,8 @@ contract Test {
     assert_eq!(
     assert_eq!(
         idl.instructions[3].accounts,
         idl.instructions[3].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "clock".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("clock", false, false),
+            idl_account("systemProgram", false, false),
         ]
         ]
     );
     );
 
 
@@ -2154,24 +1786,8 @@ contract Test {
     assert_eq!(
     assert_eq!(
         idl.instructions[4].accounts,
         idl.instructions[4].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("systemProgram", false, false),
+            idl_account("other_interface_programId", false, false),
         ]
         ]
     );
     );
 }
 }
@@ -2184,9 +1800,9 @@ fn multiple_contracts() {
 contract creator {
 contract creator {
     Child public c;
     Child public c;
 
 
-    function create_child(address child, address payer) external returns (uint64) {
+    function create_child() external returns (uint64) {
         print("Going to create child");
         print("Going to create child");
-        c = new Child{address: child}(payer);
+        c = new Child();
 
 
         return c.say_hello();
         return c.say_hello();
     }
     }
@@ -2196,7 +1812,7 @@ contract creator {
 contract Child {
 contract Child {
     @payer(payer)
     @payer(payer)
     @space(511 + 7)
     @space(511 + 7)
-    constructor(address payer) {
+    constructor() {
         print("In child constructor");
         print("In child constructor");
     }
     }
 
 
@@ -2218,42 +1834,12 @@ contract Child {
     assert_eq!(
     assert_eq!(
         idl.instructions[2].accounts,
         idl.instructions[2].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "payer".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "clock".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("dataAccount", true, false),
+            idl_account("payer", true, true),
+            idl_account("Child_dataAccount", true, true),
+            idl_account("Child_programId", false, false),
+            idl_account("systemProgram", false, false),
+            idl_account("clock", false, false),
         ]
         ]
     );
     );
 }
 }
@@ -2268,8 +1854,8 @@ contract Builder {
     BeingBuilt other;
     BeingBuilt other;
 
 
     @payer(payer_account)
     @payer(payer_account)
-    constructor(address addr) {
-        other = new BeingBuilt{address: addr}("abc");
+    constructor() {
+        other = new BeingBuilt("abc");
     }
     }
 }
 }
 
 
@@ -2294,42 +1880,12 @@ contract BeingBuilt {
     assert_eq!(
     assert_eq!(
         idl.instructions[0].accounts,
         idl.instructions[0].accounts,
         vec![
         vec![
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "dataAccount".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "payer_account".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "systemProgram".to_string(),
-                is_mut: false,
-                is_signer: false,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![],
-            }),
-            IdlAccountItem::IdlAccount(IdlAccount {
-                name: "other_account".to_string(),
-                is_mut: true,
-                is_signer: true,
-                is_optional: Some(false),
-                docs: None,
-                pda: None,
-                relations: vec![]
-            })
+            idl_account("dataAccount", true, true),
+            idl_account("payer_account", true, true),
+            idl_account("systemProgram", false, false),
+            idl_account("other_account", true, true),
+            idl_account("BeingBuilt_dataAccount", true, false),
+            idl_account("BeingBuilt_programId", false, false),
         ]
         ]
     );
     );
 }
 }
@@ -2395,3 +1951,93 @@ contract starter {
 
 
     assert_eq!(idl1, idl2);
     assert_eq!(idl1, idl2);
 }
 }
+
+#[test]
+fn account_transfer_recursive() {
+    let src = r#"
+contract CT3 {
+    CT2 ct2;
+    @payer(three_payer)
+    constructor() {
+        ct2 = new CT2();
+    }
+}
+
+@program_id("Ha2EGxARbSYpqNZkkvZUUGEyx3pu7Mg9pvMsuEJuWNjH")
+contract CT2 {
+    CT1 ct1;
+    @payer(two_payer)
+    constructor() {
+        ct1 = new CT1(block.timestamp);
+    }
+}
+
+
+@program_id("5kQ3iJ43gHNDjqmSAtE1vDu18CiSAfNbRe4v5uoobh3U")
+contract CT1 {
+    @payer(one_payer)
+    constructor(uint64 time) {
+        print("{}".format(time));
+    }
+}
+    "#;
+
+    let mut ns = generate_namespace(src);
+    codegen(&mut ns, &Options::default());
+    let ct3 = generate_anchor_idl(0, &ns, "0.1.0");
+    let ct2 = generate_anchor_idl(1, &ns, "0.1.0");
+    let ct1 = generate_anchor_idl(2, &ns, "0.1.0");
+
+    assert_eq!(ct1.instructions[0].name, "new");
+    assert_eq!(
+        ct1.instructions[0].accounts,
+        vec![
+            idl_account("dataAccount", true, true),
+            idl_account("one_payer", true, true),
+            idl_account("systemProgram", false, false),
+        ]
+    );
+
+    assert_eq!(ct2.instructions[0].name, "new");
+    assert_eq!(
+        ct2.instructions[0].accounts,
+        vec![
+            idl_account("dataAccount", true, true),
+            idl_account("two_payer", true, true),
+            idl_account("clock", false, false),
+            idl_account("one_payer", true, true),
+            idl_account("CT1_dataAccount", true, true),
+            idl_account("CT1_programId", false, false),
+            idl_account("systemProgram", false, false),
+        ]
+    );
+
+    assert_eq!(ct3.instructions[0].name, "new");
+    assert_eq!(
+        ct3.instructions[0].accounts,
+        vec![
+            idl_account("dataAccount", true, true),
+            idl_account("three_payer", true, true),
+            idl_account("systemProgram", false, false),
+            idl_account("two_payer", true, true),
+            idl_account("CT2_dataAccount", true, true),
+            idl_account("CT2_programId", false, false),
+            idl_account("clock", false, false),
+            idl_account("one_payer", true, true),
+            idl_account("CT1_dataAccount", true, true),
+            idl_account("CT1_programId", false, false),
+        ]
+    );
+}
+
+fn idl_account(name: &str, is_mut: bool, is_signer: bool) -> IdlAccountItem {
+    IdlAccountItem::IdlAccount(IdlAccount {
+        name: name.to_string(),
+        is_mut,
+        is_signer,
+        is_optional: Some(false),
+        docs: None,
+        pda: None,
+        relations: vec![],
+    })
+}

+ 0 - 3
src/bin/languageserver/mod.rs

@@ -1095,9 +1095,6 @@ impl<'a> Builder<'a> {
                 if let Some(optsalt) = &call_args.salt {
                 if let Some(optsalt) = &call_args.salt {
                     self.expression(optsalt, symtab);
                     self.expression(optsalt, symtab);
                 }
                 }
-                if let Some(address) = &call_args.address {
-                    self.expression(address, symtab);
-                }
                 if let Some(seeds) = &call_args.seeds {
                 if let Some(seeds) = &call_args.seeds {
                     self.expression(seeds, symtab);
                     self.expression(seeds, symtab);
                 }
                 }

+ 7 - 1
src/codegen/cfg.rs

@@ -132,6 +132,7 @@ pub enum Instr {
     /// Call external functions. If the call fails, set the success failure
     /// Call external functions. If the call fails, set the success failure
     /// or abort if this is None
     /// or abort if this is None
     ExternalCall {
     ExternalCall {
+        loc: Loc,
         success: Option<usize>,
         success: Option<usize>,
         address: Option<Expression>,
         address: Option<Expression>,
         accounts: Option<Expression>,
         accounts: Option<Expression>,
@@ -417,6 +418,8 @@ pub struct ControlFlowGraph {
     current: usize,
     current: usize,
     // A mapping between the res of an array and the res of the temp var holding its length.
     // A mapping between the res of an array and the res of the temp var holding its length.
     pub array_lengths_temps: ArrayLengthVars,
     pub array_lengths_temps: ArrayLengthVars,
+    /// Is this a modifier dispatch for which function number?
+    pub modifier: Option<usize>,
 }
 }
 
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -488,6 +491,7 @@ impl ControlFlowGraph {
             selector: Vec::new(),
             selector: Vec::new(),
             current: 0,
             current: 0,
             array_lengths_temps: IndexMap::new(),
             array_lengths_temps: IndexMap::new(),
+            modifier: None,
         };
         };
 
 
         cfg.new_basic_block("entry".to_string());
         cfg.new_basic_block("entry".to_string());
@@ -510,6 +514,7 @@ impl ControlFlowGraph {
             selector: Vec::new(),
             selector: Vec::new(),
             current: 0,
             current: 0,
             array_lengths_temps: IndexMap::new(),
             array_lengths_temps: IndexMap::new(),
+            modifier: None,
         }
         }
     }
     }
 
 
@@ -1181,7 +1186,7 @@ impl ControlFlowGraph {
                 gas,
                 gas,
                 callty,
                 callty,
                 contract_function_no,
                 contract_function_no,
-                flags
+                flags, ..
             } => {
             } => {
                 format!(
                 format!(
                     "{} = external call::{} address:{} payload:{} value:{} gas:{} accounts:{} seeds:{} contract|function:{} flags:{}",
                     "{} = external call::{} address:{} payload:{} value:{} gas:{} accounts:{} seeds:{} contract|function:{} flags:{}",
@@ -1511,6 +1516,7 @@ pub fn generate_cfg(
             cfg.public = public;
             cfg.public = public;
             cfg.nonpayable = nonpayable;
             cfg.nonpayable = nonpayable;
             cfg.selector = ns.functions[func_no].selector(ns, &contract_no);
             cfg.selector = ns.functions[func_no].selector(ns, &contract_no);
+            cfg.modifier = Some(func_no);
         }
         }
     }
     }
 
 

+ 2 - 0
src/codegen/constant_folding.rs

@@ -267,6 +267,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
                     }
                     }
                 }
                 }
                 Instr::ExternalCall {
                 Instr::ExternalCall {
+                    loc,
                     success,
                     success,
                     address,
                     address,
                     payload,
                     payload,
@@ -296,6 +297,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
 
 
                     if !dry_run {
                     if !dry_run {
                         cfg.blocks[block_no].instr[instr_no] = Instr::ExternalCall {
                         cfg.blocks[block_no].instr[instr_no] = Instr::ExternalCall {
+                            loc: *loc,
                             success: *success,
                             success: *success,
                             address,
                             address,
                             accounts,
                             accounts,

+ 14 - 4
src/codegen/constructor.rs

@@ -8,6 +8,8 @@ use crate::sema::{
     ast,
     ast,
     ast::{CallArgs, Function, Namespace, Type},
     ast::{CallArgs, Function, Namespace, Type},
 };
 };
+use crate::Target;
+use num_bigint::{BigInt, Sign};
 use solang_parser::pt::Loc;
 use solang_parser::pt::Loc;
 
 
 use super::encoding::abi_encode;
 use super::encoding::abi_encode;
@@ -44,10 +46,18 @@ pub(super) fn call_constructor(
         .salt
         .salt
         .as_ref()
         .as_ref()
         .map(|e| expression(e, cfg, callee_contract_no, func, ns, vartab, opt));
         .map(|e| expression(e, cfg, callee_contract_no, func, ns, vartab, opt));
-    let address = call_args
-        .address
-        .as_ref()
-        .map(|e| expression(e, cfg, callee_contract_no, func, ns, vartab, opt));
+    let address = if ns.target == Target::Solana {
+        Some(Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Address(false),
+            value: BigInt::from_bytes_be(
+                Sign::Plus,
+                ns.contracts[contract_no].program_id.as_ref().unwrap(),
+            ),
+        })
+    } else {
+        None
+    };
     let seeds = call_args
     let seeds = call_args
         .seeds
         .seeds
         .as_ref()
         .as_ref()

+ 11 - 4
src/codegen/dispatch/solana.rs

@@ -12,6 +12,7 @@ use num_traits::Zero;
 use solang_parser::{pt, pt::Loc};
 use solang_parser::{pt, pt::Loc};
 
 
 use crate::codegen::encoding::{abi_decode, abi_encode};
 use crate::codegen::encoding::{abi_decode, abi_encode};
+use crate::sema::solana_accounts::BuiltinAccounts;
 
 
 pub const SOLANA_DISPATCH_CFG_NAME: &str = "solang_dispatch";
 pub const SOLANA_DISPATCH_CFG_NAME: &str = "solang_dispatch";
 
 
@@ -268,13 +269,19 @@ fn add_function_dispatch_case(
     let entry = cfg.new_basic_block(format!("function_cfg_{cfg_no}"));
     let entry = cfg.new_basic_block(format!("function_cfg_{cfg_no}"));
     cfg.set_basic_block(entry);
     cfg.set_basic_block(entry);
 
 
-    let needs_account = if let ASTFunction::SolidityFunction(func_no) = func_cfg.function_no {
-        !ns.functions[func_no].is_pure()
+    let ast_func_no = if let ASTFunction::SolidityFunction(func_no) = func_cfg.function_no {
+        func_no
+    } else if let Some(func_no) = func_cfg.modifier {
+        func_no
     } else {
     } else {
-        true
+        unreachable!("should not dispatch this function")
     };
     };
 
 
-    if needs_account {
+    if ns.functions[ast_func_no]
+        .solana_accounts
+        .borrow()
+        .contains_key(BuiltinAccounts::DataAccount.as_str())
+    {
         check_magic(ns.contracts[contract_no].selector(), cfg, vartab);
         check_magic(ns.contracts[contract_no].selector(), cfg, vartab);
     }
     }
 
 

+ 14 - 1
src/codegen/expression.rs

@@ -28,7 +28,7 @@ use crate::sema::{
     expression::ResolveTo,
     expression::ResolveTo,
 };
 };
 use crate::Target;
 use crate::Target;
-use num_bigint::BigInt;
+use num_bigint::{BigInt, Sign};
 use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
 use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
 use solang_parser::pt;
 use solang_parser::pt;
 use solang_parser::pt::{CodeLocation, Loc};
 use solang_parser::pt::{CodeLocation, Loc};
@@ -1589,6 +1589,7 @@ fn payable_send(
         cfg.add(
         cfg.add(
             vartab,
             vartab,
             Instr::ExternalCall {
             Instr::ExternalCall {
+                loc: *loc,
                 success: Some(success),
                 success: Some(success),
                 address: Some(address),
                 address: Some(address),
                 accounts: None,
                 accounts: None,
@@ -1658,6 +1659,7 @@ fn payable_transfer(
         cfg.add(
         cfg.add(
             vartab,
             vartab,
             Instr::ExternalCall {
             Instr::ExternalCall {
+                loc: *loc,
                 success: None,
                 success: None,
                 accounts: None,
                 accounts: None,
                 seeds: None,
                 seeds: None,
@@ -2162,6 +2164,14 @@ fn expr_builtin(
             }
             }
         }
         }
         ast::Builtin::GetAddress => {
         ast::Builtin::GetAddress => {
+            if let Some(constant_id) = &ns.contracts[contract_no].program_id {
+                return Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: Type::Address(false),
+                    value: BigInt::from_bytes_be(Sign::Plus, constant_id),
+                };
+            }
+
             // In emit, GetAddress returns a pointer to the address
             // In emit, GetAddress returns a pointer to the address
             let codegen_expr = Expression::Builtin {
             let codegen_expr = Expression::Builtin {
                 loc: *loc,
                 loc: *loc,
@@ -2794,6 +2804,7 @@ pub fn emit_function_call(
             cfg.add(
             cfg.add(
                 vartab,
                 vartab,
                 Instr::ExternalCall {
                 Instr::ExternalCall {
+                    loc: *loc,
                     success: Some(success),
                     success: Some(success),
                     address: Some(address),
                     address: Some(address),
                     payload: args,
                     payload: args,
@@ -2908,6 +2919,7 @@ pub fn emit_function_call(
                 cfg.add(
                 cfg.add(
                     vartab,
                     vartab,
                     Instr::ExternalCall {
                     Instr::ExternalCall {
+                        loc: *loc,
                         success,
                         success,
                         accounts,
                         accounts,
                         address: Some(address),
                         address: Some(address),
@@ -2994,6 +3006,7 @@ pub fn emit_function_call(
                 cfg.add(
                 cfg.add(
                     vartab,
                     vartab,
                     Instr::ExternalCall {
                     Instr::ExternalCall {
+                        loc: *loc,
                         success,
                         success,
                         accounts: None,
                         accounts: None,
                         seeds: None,
                         seeds: None,

+ 1 - 2
src/codegen/mod.rs

@@ -179,6 +179,7 @@ pub fn codegen(ns: &mut Namespace, opt: &Options) {
             }
             }
         }
         }
     }
     }
+    ns.diagnostics.sort_and_dedup();
 }
 }
 
 
 fn contract(contract_no: usize, ns: &mut Namespace, opt: &Options) {
 fn contract(contract_no: usize, ns: &mut Namespace, opt: &Options) {
@@ -1755,7 +1756,6 @@ pub enum Builtin {
     Ripemd160,
     Ripemd160,
     Sender,
     Sender,
     Slot,
     Slot,
-    ProgramId,
     Sha256,
     Sha256,
     Signature,
     Signature,
     SignatureVerify,
     SignatureVerify,
@@ -1813,7 +1813,6 @@ impl From<&ast::Builtin> for Builtin {
             ast::Builtin::Ripemd160 => Builtin::Ripemd160,
             ast::Builtin::Ripemd160 => Builtin::Ripemd160,
             ast::Builtin::Sender => Builtin::Sender,
             ast::Builtin::Sender => Builtin::Sender,
             ast::Builtin::Slot => Builtin::Slot,
             ast::Builtin::Slot => Builtin::Slot,
-            ast::Builtin::ProgramId => Builtin::ProgramId,
             ast::Builtin::Sha256 => Builtin::Sha256,
             ast::Builtin::Sha256 => Builtin::Sha256,
             ast::Builtin::Signature => Builtin::Signature,
             ast::Builtin::Signature => Builtin::Signature,
             ast::Builtin::SignatureVerify => Builtin::SignatureVerify,
             ast::Builtin::SignatureVerify => Builtin::SignatureVerify,

+ 115 - 86
src/codegen/solana_accounts/account_collection.rs

@@ -3,12 +3,13 @@
 use crate::codegen::cfg::{ASTFunction, ControlFlowGraph, Instr, InternalCallTy};
 use crate::codegen::cfg::{ASTFunction, ControlFlowGraph, Instr, InternalCallTy};
 use crate::codegen::solana_accounts::account_from_number;
 use crate::codegen::solana_accounts::account_from_number;
 use crate::codegen::{Builtin, Expression};
 use crate::codegen::{Builtin, Expression};
-use crate::sema::ast::{Contract, Function, Mutability, Namespace, SolanaAccount};
+use crate::sema::ast::{Contract, Function, Namespace, SolanaAccount};
 use crate::sema::diagnostics::Diagnostics;
 use crate::sema::diagnostics::Diagnostics;
 use crate::sema::solana_accounts::BuiltinAccounts;
 use crate::sema::solana_accounts::BuiltinAccounts;
 use crate::sema::Recurse;
 use crate::sema::Recurse;
 use indexmap::IndexSet;
 use indexmap::IndexSet;
 use solang_parser::diagnostics::Diagnostic;
 use solang_parser::diagnostics::Diagnostic;
+use solang_parser::pt;
 use solang_parser::pt::{FunctionTy, Loc};
 use solang_parser::pt::{FunctionTy, Loc};
 use std::collections::{HashSet, VecDeque};
 use std::collections::{HashSet, VecDeque};
 
 
@@ -33,7 +34,7 @@ struct RecurseData<'a> {
 
 
 impl RecurseData<'_> {
 impl RecurseData<'_> {
     /// Add an account to the function's indexmap
     /// Add an account to the function's indexmap
-    fn add_account(&mut self, account_name: String, account: SolanaAccount) {
+    fn add_account(&mut self, account_name: String, account: &SolanaAccount) {
         let (is_signer, is_writer) = self.functions[self.ast_no]
         let (is_signer, is_writer) = self.functions[self.ast_no]
             .solana_accounts
             .solana_accounts
             .borrow()
             .borrow()
@@ -63,7 +64,7 @@ impl RecurseData<'_> {
     fn add_system_account(&mut self) {
     fn add_system_account(&mut self) {
         self.add_account(
         self.add_account(
             BuiltinAccounts::SystemAccount.to_string(),
             BuiltinAccounts::SystemAccount.to_string(),
-            SolanaAccount {
+            &SolanaAccount {
                 loc: Loc::Codegen,
                 loc: Loc::Codegen,
                 is_writer: false,
                 is_writer: false,
                 is_signer: false,
                 is_signer: false,
@@ -86,41 +87,17 @@ pub(crate) fn collect_accounts_from_contract(contract_no: usize, ns: &Namespace)
             )
             )
         {
         {
             let func = &ns.functions[*func_no];
             let func = &ns.functions[*func_no];
-            match &func.mutability {
-                Mutability::Pure(_) => (),
-                Mutability::View(_) => {
-                    let (idx, _) = func.solana_accounts.borrow_mut().insert_full(
-                        BuiltinAccounts::DataAccount.to_string(),
-                        SolanaAccount {
-                            loc: Loc::Codegen,
-                            is_writer: false,
-                            is_signer: false,
-                            generated: true,
-                        },
-                    );
-                    func.solana_accounts.borrow_mut().move_index(idx, 0);
-                }
-                _ => {
-                    let (idx, _) = func.solana_accounts.borrow_mut().insert_full(
-                        BuiltinAccounts::DataAccount.to_string(),
-                        SolanaAccount {
-                            loc: Loc::Codegen,
-                            is_writer: true,
-                            /// With a @payer annotation, the account is created on-chain and needs a signer. The client
-                            /// provides an address that does not exist yet, so SystemProgram.CreateAccount is called
-                            /// on-chain.
-                            ///
-                            /// However, if a @seed is also provided, the program can sign for the account
-                            /// with the seed using program derived address (pda) when SystemProgram.CreateAccount is called,
-                            /// so no signer is required from the client.
-                            is_signer: func.has_payer_annotation() && !func.has_seed_annotation(),
-                            generated: true,
-                        },
-                    );
-
-                    func.solana_accounts.borrow_mut().move_index(idx, 0);
-                }
+            let index = func
+                .solana_accounts
+                .borrow()
+                .get_index_of(BuiltinAccounts::DataAccount.as_str());
+            if let Some(data_account_index) = index {
+                // Enforce the data account to be the first
+                func.solana_accounts
+                    .borrow_mut()
+                    .move_index(data_account_index, 0);
             }
             }
+
             if func.is_constructor() && func.has_payer_annotation() {
             if func.is_constructor() && func.has_payer_annotation() {
                 func.solana_accounts.borrow_mut().insert(
                 func.solana_accounts.borrow_mut().insert(
                     BuiltinAccounts::SystemAccount.to_string(),
                     BuiltinAccounts::SystemAccount.to_string(),
@@ -234,7 +211,7 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
                         let accounts_to_add =
                         let accounts_to_add =
                             data.functions[*ast_no].solana_accounts.borrow().clone();
                             data.functions[*ast_no].solana_accounts.borrow().clone();
                         for (account_name, account) in accounts_to_add {
                         for (account_name, account) in accounts_to_add {
-                            data.add_account(account_name, account);
+                            data.add_account(account_name, &account);
                         }
                         }
                     }
                     }
                     _ => (),
                     _ => (),
@@ -324,6 +301,7 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
             value.recurse(data, check_expression);
             value.recurse(data, check_expression);
         }
         }
         Instr::Constructor {
         Instr::Constructor {
+            loc,
             encoded_args,
             encoded_args,
             value,
             value,
             gas,
             gas,
@@ -332,6 +310,7 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
             seeds,
             seeds,
             accounts,
             accounts,
             constructor_no,
             constructor_no,
+            contract_no,
             ..
             ..
         } => {
         } => {
             encoded_args.recurse(data, check_expression);
             encoded_args.recurse(data, check_expression);
@@ -354,43 +333,14 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
                 // If the one passes the AccountMeta vector to the constructor call, there is no
                 // If the one passes the AccountMeta vector to the constructor call, there is no
                 // need to collect accounts for the IDL.
                 // need to collect accounts for the IDL.
                 if let Some(constructor_no) = constructor_no {
                 if let Some(constructor_no) = constructor_no {
-                    let accounts_to_add = data.functions[*constructor_no]
-                        .solana_accounts
-                        .borrow()
-                        .clone();
-                    for (name, account) in accounts_to_add {
-                        if name == BuiltinAccounts::DataAccount {
-                            continue;
-                        }
-
-                        if let Some(other_account) = data.functions[data.ast_no]
-                            .solana_accounts
-                            .borrow()
-                            .get(&name)
-                        {
-                            // If the compiler did not generate this account entry, we have a name
-                            // collision.
-                            if !other_account.generated {
-                                data.diagnostics.push(
-                                    Diagnostic::error_with_note(
-                                        other_account.loc,
-                                        "account name collision encountered. Calling a function that \
-                                requires an account whose name is also defined in the current function \
-                                will create duplicate names in the IDL. Please, rename one of the accounts".to_string(),
-                                        account.loc,
-                                        "other declaration".to_string()
-                                    )
-                                );
-                            }
-                        }
-                        data.add_account(name, account);
-                    }
+                    transfer_accounts(loc, *contract_no, *constructor_no, data, false);
                 }
                 }
             }
             }
 
 
             data.add_system_account();
             data.add_system_account();
         }
         }
         Instr::ExternalCall {
         Instr::ExternalCall {
+            loc,
             address,
             address,
             accounts,
             accounts,
             seeds,
             seeds,
@@ -400,6 +350,14 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
             contract_function_no,
             contract_function_no,
             ..
             ..
         } => {
         } => {
+            // When we generate an external call in codegen, we have already taken care of the
+            // accounts we need (the payer for deploying creating the data accounts and the system
+            // program).
+            if *loc == Loc::Codegen {
+                return;
+            }
+
+            let mut program_id_populated = false;
             if let Some(address) = address {
             if let Some(address) = address {
                 address.recurse(data, check_expression);
                 address.recurse(data, check_expression);
                 if let Expression::NumberLiteral { value, .. } = address {
                 if let Expression::NumberLiteral { value, .. } = address {
@@ -407,19 +365,17 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
                     if let Some(account) = account_from_number(value) {
                     if let Some(account) = account_from_number(value) {
                         data.add_account(
                         data.add_account(
                             account,
                             account,
-                            SolanaAccount {
+                            &SolanaAccount {
                                 loc: Loc::Codegen,
                                 loc: Loc::Codegen,
                                 is_signer: false,
                                 is_signer: false,
                                 is_writer: false,
                                 is_writer: false,
                                 generated: true,
                                 generated: true,
                             },
                             },
                         );
                         );
+                        program_id_populated = true;
                     }
                     }
                 }
                 }
             }
             }
-            if let Some(accounts) = accounts {
-                accounts.recurse(data, check_expression);
-            }
             if let Some(seeds) = seeds {
             if let Some(seeds) = seeds {
                 seeds.recurse(data, check_expression);
                 seeds.recurse(data, check_expression);
             }
             }
@@ -428,17 +384,11 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
             gas.recurse(data, check_expression);
             gas.recurse(data, check_expression);
             // External calls always need the system account
             // External calls always need the system account
             data.add_system_account();
             data.add_system_account();
-            if let Some((contract_no, function_no)) = contract_function_no {
-                let cfg_no = data.contracts[*contract_no].all_functions[function_no];
-                let accounts_to_add = data.functions[*function_no]
-                    .solana_accounts
-                    .borrow()
-                    .clone();
-                for (account_name, account) in accounts_to_add {
-                    data.add_account(account_name, account);
-                }
-                data.next_queue.insert((*contract_no, cfg_no));
-                data.next_queue.insert((data.contract_no, data.cfg_func_no));
+
+            if let Some(accounts) = accounts {
+                accounts.recurse(data, check_expression);
+            } else if let Some((contract_no, function_no)) = contract_function_no {
+                transfer_accounts(loc, *contract_no, *function_no, data, program_id_populated);
             }
             }
         }
         }
         Instr::EmitEvent {
         Instr::EmitEvent {
@@ -471,7 +421,7 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
         } => {
         } => {
             data.add_account(
             data.add_account(
                 BuiltinAccounts::ClockAccount.to_string(),
                 BuiltinAccounts::ClockAccount.to_string(),
-                SolanaAccount {
+                &SolanaAccount {
                     loc: Loc::Codegen,
                     loc: Loc::Codegen,
                     is_signer: false,
                     is_signer: false,
                     is_writer: false,
                     is_writer: false,
@@ -485,7 +435,7 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
         } => {
         } => {
             data.add_account(
             data.add_account(
                 BuiltinAccounts::InstructionAccount.to_string(),
                 BuiltinAccounts::InstructionAccount.to_string(),
-                SolanaAccount {
+                &SolanaAccount {
                     loc: Loc::Codegen,
                     loc: Loc::Codegen,
                     is_writer: false,
                     is_writer: false,
                     is_signer: false,
                     is_signer: false,
@@ -505,3 +455,82 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
 
 
     true
     true
 }
 }
+
+/// When we make an external call from function A to function B, function A must know all the
+/// accounts function B needs. The 'transfer_accounts' function takes care to transfer the accounts
+/// from B's IDL to A's IDL.
+fn transfer_accounts(
+    loc: &pt::Loc,
+    contract_no: usize,
+    function_no: usize,
+    data: &mut RecurseData,
+    program_id_present: bool,
+) {
+    let accounts_to_add = data.functions[function_no].solana_accounts.borrow().clone();
+
+    for (name, mut account) in accounts_to_add {
+        if name == BuiltinAccounts::DataAccount {
+            let idl_name = format!("{}_dataAccount", data.contracts[contract_no].name);
+            if let Some(acc) = data.functions[data.ast_no]
+                .solana_accounts
+                .borrow()
+                .get(&idl_name)
+            {
+                if acc.loc != *loc {
+                    data.diagnostics.push(
+                        Diagnostic::error_with_note(
+                            *loc,
+                            format!("contract '{}' is called more than once in this function, so automatic account collection cannot happen. \
+                                         Please, provide the necessary accounts using the {{accounts:..}} call argument", data.contracts[contract_no].name),
+                            acc.loc,
+                            "other call".to_string(),
+                        )
+                    );
+                }
+                continue;
+            }
+            account.loc = *loc;
+            data.add_account(idl_name, &account);
+            continue;
+        }
+
+        if let Some(other_account) = data.functions[data.ast_no]
+            .solana_accounts
+            .borrow()
+            .get(&name)
+        {
+            if !other_account.generated {
+                data.diagnostics.push(
+                    Diagnostic::error_with_note(
+                        other_account.loc,
+                        "account name collision encountered. Calling a function that \
+                                requires an account whose name is also defined in the current function \
+                                will create duplicate names in the IDL. Please, rename one of the accounts".to_string(),
+                        account.loc,
+                        "other declaration".to_string(),
+                    )
+                );
+            }
+        }
+        data.add_account(name, &account);
+    }
+
+    if !program_id_present {
+        data.functions[data.ast_no]
+            .solana_accounts
+            .borrow_mut()
+            .insert(
+                format!("{}_programId", data.contracts[contract_no].name),
+                SolanaAccount {
+                    is_signer: false,
+                    is_writer: false,
+                    generated: true,
+                    loc: *loc,
+                },
+            );
+    }
+
+    let cfg_no = data.contracts[contract_no].all_functions[&function_no];
+    data.next_queue.insert((contract_no, cfg_no));
+    data.next_queue.insert((data.contract_no, data.cfg_func_no));
+}

+ 101 - 78
src/codegen/solana_accounts/account_management.rs

@@ -1,12 +1,11 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
-use crate::codegen::cfg::{ControlFlowGraph, Instr};
+use crate::codegen::cfg::Instr;
 use crate::codegen::dispatch::solana::SOLANA_DISPATCH_CFG_NAME;
 use crate::codegen::dispatch::solana::SOLANA_DISPATCH_CFG_NAME;
 use crate::codegen::{Builtin, Expression};
 use crate::codegen::{Builtin, Expression};
-use crate::sema::ast::{ArrayLength, Function, Namespace, StructType, Type};
+use crate::sema::ast::{ArrayLength, Contract, Function, Namespace, StructType, Type};
 use crate::sema::solana_accounts::BuiltinAccounts;
 use crate::sema::solana_accounts::BuiltinAccounts;
 use num_bigint::BigInt;
 use num_bigint::BigInt;
-use num_traits::Zero;
 use solang_parser::pt::Loc;
 use solang_parser::pt::Loc;
 use std::collections::{HashSet, VecDeque};
 use std::collections::{HashSet, VecDeque};
 
 
@@ -26,8 +25,10 @@ pub(crate) fn manage_contract_accounts(contract_no: usize, ns: &mut Namespace) {
             .copied()
             .copied()
             .unwrap();
             .unwrap();
         traverse_cfg(
         traverse_cfg(
-            &mut ns.contracts[contract_no].cfg[cfg_no],
+            &mut ns.contracts,
+            contract_no,
             &ns.functions,
             &ns.functions,
+            cfg_no,
             *function_no,
             *function_no,
         );
         );
     }
     }
@@ -35,16 +36,28 @@ pub(crate) fn manage_contract_accounts(contract_no: usize, ns: &mut Namespace) {
     if let Some(constructor) = constructor_no {
     if let Some(constructor) = constructor_no {
         let dispatch = ns.contracts[contract_no]
         let dispatch = ns.contracts[contract_no]
             .cfg
             .cfg
-            .iter_mut()
-            .find(|cfg| cfg.name == SOLANA_DISPATCH_CFG_NAME)
+            .iter()
+            .position(|cfg| cfg.name == SOLANA_DISPATCH_CFG_NAME)
             .expect("dispatch CFG is always generated");
             .expect("dispatch CFG is always generated");
-        traverse_cfg(dispatch, &ns.functions, constructor);
+        traverse_cfg(
+            &mut ns.contracts,
+            contract_no,
+            &ns.functions,
+            dispatch,
+            constructor,
+        );
     }
     }
 }
 }
 
 
 /// This function walks over the CFG to process its instructions for the account management.
 /// This function walks over the CFG to process its instructions for the account management.
-fn traverse_cfg(cfg: &mut ControlFlowGraph, functions: &[Function], ast_no: usize) {
-    if cfg.blocks.is_empty() {
+fn traverse_cfg(
+    contracts: &mut [Contract],
+    contract_no: usize,
+    functions: &[Function],
+    cfg_no: usize,
+    ast_no: usize,
+) {
+    if contracts[contract_no].cfg[cfg_no].blocks.is_empty() {
         return;
         return;
     }
     }
 
 
@@ -54,11 +67,22 @@ fn traverse_cfg(cfg: &mut ControlFlowGraph, functions: &[Function], ast_no: usiz
     visited.insert(0);
     visited.insert(0);
 
 
     while let Some(cur_block) = queue.pop_front() {
     while let Some(cur_block) = queue.pop_front() {
-        for instr in cfg.blocks[cur_block].instr.iter_mut() {
-            process_instruction(instr, functions, ast_no);
+        for instr_no in 0..contracts[contract_no].cfg[cfg_no].blocks[cur_block]
+            .instr
+            .len()
+        {
+            process_instruction(
+                cfg_no,
+                instr_no,
+                cur_block,
+                functions,
+                contracts,
+                ast_no,
+                contract_no,
+            );
         }
         }
 
 
-        for edge in cfg.blocks[cur_block].successors() {
+        for edge in contracts[contract_no].cfg[cfg_no].blocks[cur_block].successors() {
             if !visited.contains(&edge) {
             if !visited.contains(&edge) {
                 queue.push_back(edge);
                 queue.push_back(edge);
                 visited.insert(edge);
                 visited.insert(edge);
@@ -69,48 +93,45 @@ fn traverse_cfg(cfg: &mut ControlFlowGraph, functions: &[Function], ast_no: usiz
 
 
 /// This function processes the instruction, creating the AccountMeta array when possible.
 /// This function processes the instruction, creating the AccountMeta array when possible.
 /// Presently, we only check the Instr::Constructor, but more will come later.
 /// Presently, we only check the Instr::Constructor, but more will come later.
-fn process_instruction(instr: &mut Instr, functions: &[Function], ast_no: usize) {
-    if let Instr::Constructor {
-        accounts,
-        address,
-        constructor_no,
-        ..
-    } = instr
-    {
-        if accounts.is_some() || constructor_no.is_none() {
-            return;
+fn process_instruction(
+    cfg_no: usize,
+    instr_no: usize,
+    block_no: usize,
+    functions: &[Function],
+    contracts: &mut [Contract],
+    ast_no: usize,
+    contract_no: usize,
+) {
+    let instr = &mut contracts[contract_no].cfg[cfg_no].blocks[block_no].instr[instr_no];
+    match instr {
+        Instr::Constructor {
+            accounts,
+            constructor_no: Some(func_no),
+            contract_no,
+            ..
         }
         }
+        | Instr::ExternalCall {
+            accounts,
+            contract_function_no: Some((contract_no, func_no)),
+            ..
+        } => {
+            if accounts.is_some() {
+                return;
+            }
 
 
-        let mut account_metas: Vec<Expression> = Vec::new();
-        let constructor_func = &functions[constructor_no.unwrap()];
-        for (name, account) in constructor_func.solana_accounts.borrow().iter() {
-            if name == BuiltinAccounts::DataAccount {
-                let address_ref = Expression::GetRef {
-                    loc: Loc::Codegen,
-                    ty: Type::Ref(Box::new(Type::Address(false))),
-                    expr: Box::new(address.as_ref().unwrap().clone()),
-                };
-                let struct_literal =
-                    account_meta_literal(address_ref, account.is_signer, account.is_writer);
-                account_metas.push(struct_literal);
-            } else if name == BuiltinAccounts::SystemAccount {
-                let system_address = Expression::NumberLiteral {
-                    loc: Loc::Codegen,
-                    ty: Type::Address(false),
-                    value: BigInt::zero(),
-                };
-                let system_ref = Expression::GetRef {
-                    loc: Loc::Codegen,
-                    ty: Type::Ref(Box::new(Type::Address(false))),
-                    expr: Box::new(system_address),
+            let mut account_metas: Vec<Expression> = Vec::new();
+            let constructor_func = &functions[*func_no];
+            for (name, account) in constructor_func.solana_accounts.borrow().iter() {
+                let name_to_index = if name == BuiltinAccounts::DataAccount {
+                    format!("{}_dataAccount", contracts[*contract_no].name)
+                } else {
+                    name.clone()
                 };
                 };
-                let struct_literal = account_meta_literal(system_ref, false, false);
-                account_metas.push(struct_literal);
-            } else {
+
                 let account_index = functions[ast_no]
                 let account_index = functions[ast_no]
                     .solana_accounts
                     .solana_accounts
                     .borrow()
                     .borrow()
-                    .get_index_of(name)
+                    .get_index_of(&name_to_index)
                     .unwrap();
                     .unwrap();
                 let ptr_to_address = accounts_vector_key_at_index(account_index);
                 let ptr_to_address = accounts_vector_key_at_index(account_index);
                 account_metas.push(account_meta_literal(
                 account_metas.push(account_meta_literal(
@@ -119,38 +140,40 @@ fn process_instruction(instr: &mut Instr, functions: &[Function], ast_no: usize)
                     account.is_writer,
                     account.is_writer,
                 ));
                 ));
             }
             }
+
+            let metas_vector = Expression::ArrayLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Array(
+                    Box::new(Type::Struct(StructType::AccountMeta)),
+                    vec![ArrayLength::Fixed(BigInt::from(account_metas.len()))],
+                ),
+                dimensions: vec![account_metas.len() as u32],
+                values: account_metas,
+            };
+            *accounts = Some(metas_vector);
+        }
+        Instr::AccountAccess { loc, name, var_no } => {
+            // This could have been an Expression::AccountAccess if we had a three-address form.
+            // The amount of code necessary to traverse all Instructions and all expressions recursively
+            // (Expressions form a tree) makes the usage of Expression::AccountAccess too burdensome.
+
+            // Alternatively, we can create a codegen::Expression::AccountAccess when we have the
+            // new SSA IR complete.
+            let account_index = functions[ast_no]
+                .solana_accounts
+                .borrow()
+                .get_index_of(name)
+                .unwrap();
+            let expr = index_accounts_vector(account_index);
+
+            *instr = Instr::Set {
+                loc: *loc,
+                res: *var_no,
+                expr,
+            };
         }
         }
-        let metas_vector = Expression::ArrayLiteral {
-            loc: Loc::Codegen,
-            ty: Type::Array(
-                Box::new(Type::Struct(StructType::AccountMeta)),
-                vec![ArrayLength::Fixed(BigInt::from(account_metas.len()))],
-            ),
-            dimensions: vec![account_metas.len() as u32],
-            values: account_metas,
-        };
-
-        *address = None;
-        *accounts = Some(metas_vector);
-    } else if let Instr::AccountAccess { loc, name, var_no } = instr {
-        // This could have been an Expression::AccountAccess if we had a three-address form.
-        // The amount of code necessary to traverse all Instructions and all expressions recursively
-        // (Expressions form a tree) makes the usage of Expression::AccountAccess too burdensome.
-
-        // Alternatively, we can create a codegen::Expression::AccountAccess when we have the
-        // new SSA IR complete.
-        let account_index = functions[ast_no]
-            .solana_accounts
-            .borrow()
-            .get_index_of(name)
-            .unwrap();
-        let expr = index_accounts_vector(account_index);
 
 
-        *instr = Instr::Set {
-            loc: *loc,
-            res: *var_no,
-            expr,
-        };
+        _ => (),
     }
     }
 }
 }
 
 

+ 38 - 19
src/codegen/solana_deploy.rs

@@ -11,6 +11,7 @@ use crate::sema::ast::{
     self, ArrayLength, CallTy, ConstructorAnnotation, Function, FunctionAttributes, Namespace,
     self, ArrayLength, CallTy, ConstructorAnnotation, Function, FunctionAttributes, Namespace,
     StructType,
     StructType,
 };
 };
+use crate::sema::solana_accounts::BuiltinAccounts;
 use base58::ToBase58;
 use base58::ToBase58;
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
 use num_traits::{ToPrimitive, Zero};
 use num_traits::{ToPrimitive, Zero};
@@ -49,12 +50,17 @@ pub(super) fn solana_deploy(
                 ty: Type::Address(false),
                 ty: Type::Address(false),
                 value: BigInt::from_bytes_be(Sign::Plus, program_id),
                 value: BigInt::from_bytes_be(Sign::Plus, program_id),
             }),
             }),
-            right: Box::new(Expression::Builtin {
+            right: Expression::Load {
                 loc: Loc::Codegen,
                 loc: Loc::Codegen,
-                tys: vec![Type::Address(false)],
-                kind: Builtin::ProgramId,
-                args: Vec::new(),
-            }),
+                ty: Type::Address(false),
+                expr: Box::new(Expression::Builtin {
+                    loc: Loc::Codegen,
+                    tys: vec![Type::Ref(Box::new(Type::Address(false)))],
+                    kind: Builtin::GetAddress,
+                    args: Vec::new(),
+                }),
+            }
+            .into(),
         };
         };
 
 
         let id_fail = cfg.new_basic_block("program_id_fail".to_string());
         let id_fail = cfg.new_basic_block("program_id_fail".to_string());
@@ -265,14 +271,30 @@ pub(super) fn solana_deploy(
                 var_no: account_info_var,
                 var_no: account_info_var,
             },
             },
         );
         );
+        let data_account_info_var = vartab.temp_anonymous(&account_info_ty);
+        cfg.add(
+            vartab,
+            Instr::AccountAccess {
+                loc: Loc::Codegen,
+                name: BuiltinAccounts::DataAccount.to_string(),
+                var_no: data_account_info_var,
+            },
+        );
 
 
         let account_var = Expression::Variable {
         let account_var = Expression::Variable {
             loc: Loc::Codegen,
             loc: Loc::Codegen,
-            ty: account_info_ty,
+            ty: account_info_ty.clone(),
             var_no: account_info_var,
             var_no: account_info_var,
         };
         };
 
 
+        let data_acc_var = Expression::Variable {
+            loc: Loc::Codegen,
+            ty: account_info_ty,
+            var_no: data_account_info_var,
+        };
+
         let ptr_to_address = retrieve_key_from_account_info(account_var);
         let ptr_to_address = retrieve_key_from_account_info(account_var);
+        let ptr_to_data_acc = retrieve_key_from_account_info(data_acc_var);
 
 
         cfg.add(
         cfg.add(
             vartab,
             vartab,
@@ -285,16 +307,7 @@ pub(super) fn solana_deploy(
                     dimensions: vec![2],
                     dimensions: vec![2],
                     values: vec![
                     values: vec![
                         account_meta_literal(ptr_to_address, true, true),
                         account_meta_literal(ptr_to_address, true, true),
-                        account_meta_literal(
-                            Expression::Builtin {
-                                loc: Loc::Codegen,
-                                tys: vec![Type::Ref(Box::new(Type::Address(false)))],
-                                kind: Builtin::GetAddress,
-                                args: vec![],
-                            },
-                            true,
-                            true,
-                        ),
+                        account_meta_literal(ptr_to_data_acc, true, true),
                     ],
                     ],
                 },
                 },
             },
             },
@@ -460,11 +473,16 @@ pub(super) fn solana_deploy(
                         value: BigInt::from_bytes_be(Sign::Plus, program_id),
                         value: BigInt::from_bytes_be(Sign::Plus, program_id),
                     }
                     }
                 } else {
                 } else {
-                    Expression::Builtin {
+                    let addr_ptr = Expression::Builtin {
                         loc: Loc::Codegen,
                         loc: Loc::Codegen,
-                        tys: vec![Type::Address(false)],
-                        kind: Builtin::ProgramId,
+                        tys: vec![Type::Ref(Box::new(Type::Address(false)))],
+                        kind: Builtin::GetAddress,
                         args: vec![],
                         args: vec![],
+                    };
+                    Expression::Load {
+                        loc: Loc::Codegen,
+                        ty: Type::Address(false),
+                        expr: Box::new(addr_ptr),
                     }
                     }
                 },
                 },
                 offset: Expression::NumberLiteral {
                 offset: Expression::NumberLiteral {
@@ -537,6 +555,7 @@ pub(super) fn solana_deploy(
         cfg.add(
         cfg.add(
             vartab,
             vartab,
             Instr::ExternalCall {
             Instr::ExternalCall {
+                loc: Loc::Codegen,
                 success: None,
                 success: None,
                 seeds,
                 seeds,
                 address: Some(Expression::NumberLiteral {
                 address: Some(Expression::NumberLiteral {

+ 1 - 0
src/codegen/statements/try_catch.rs

@@ -257,6 +257,7 @@ fn exec_try(
                 cfg.add(
                 cfg.add(
                     vartab,
                     vartab,
                     Instr::ExternalCall {
                     Instr::ExternalCall {
+                        loc: *loc,
                         success: Some(success),
                         success: Some(success),
                         address: Some(address),
                         address: Some(address),
                         accounts: None,
                         accounts: None,

+ 2 - 0
src/codegen/subexpression_elimination/instruction.rs

@@ -376,6 +376,7 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
             }
             }
 
 
             Instr::ExternalCall {
             Instr::ExternalCall {
+                loc,
                 success,
                 success,
                 address,
                 address,
                 accounts,
                 accounts,
@@ -404,6 +405,7 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
                     .map(|expr| self.regenerate_expression(expr, ave, cst).1);
                     .map(|expr| self.regenerate_expression(expr, ave, cst).1);
 
 
                 Instr::ExternalCall {
                 Instr::ExternalCall {
+                    loc: *loc,
                     success: *success,
                     success: *success,
                     address: new_address,
                     address: new_address,
                     accounts: new_accounts,
                     accounts: new_accounts,

+ 3 - 5
src/emit/solana/mod.rs

@@ -1054,7 +1054,6 @@ impl SolanaTarget {
     fn build_external_call<'b>(
     fn build_external_call<'b>(
         &self,
         &self,
         binary: &Binary,
         binary: &Binary,
-        address: PointerValue<'b>,
         payload: PointerValue<'b>,
         payload: PointerValue<'b>,
         payload_len: IntValue<'b>,
         payload_len: IntValue<'b>,
         contract_args: ContractArgs<'b>,
         contract_args: ContractArgs<'b>,
@@ -1077,16 +1076,16 @@ impl SolanaTarget {
                     seeds,
                     seeds,
                     binary.builder.build_int_cast(
                     binary.builder.build_int_cast(
                         len,
                         len,
-                        external_call.get_type().get_param_types()[5].into_int_type(),
+                        external_call.get_type().get_param_types()[4].into_int_type(),
                         "len",
                         "len",
                     ),
                     ),
                 )
                 )
             })
             })
             .unwrap_or((
             .unwrap_or((
-                external_call.get_type().get_param_types()[4]
+                external_call.get_type().get_param_types()[3]
                     .ptr_type(AddressSpace::default())
                     .ptr_type(AddressSpace::default())
                     .const_null(),
                     .const_null(),
-                external_call.get_type().get_param_types()[5]
+                external_call.get_type().get_param_types()[4]
                     .into_int_type()
                     .into_int_type()
                     .const_zero(),
                     .const_zero(),
             ));
             ));
@@ -1096,7 +1095,6 @@ impl SolanaTarget {
             &[
             &[
                 payload.into(),
                 payload.into(),
                 payload_len.into(),
                 payload_len.into(),
-                address.into(),
                 program_id.into(),
                 program_id.into(),
                 seeds.into(),
                 seeds.into(),
                 seeds_len.into(),
                 seeds_len.into(),

+ 19 - 61
src/emit/solana/target.rs

@@ -10,8 +10,7 @@ use crate::emit::{ContractArgs, TargetRuntime, Variable};
 use crate::sema::ast::{self, Namespace};
 use crate::sema::ast::{self, Namespace};
 use inkwell::types::{BasicType, BasicTypeEnum, IntType};
 use inkwell::types::{BasicType, BasicTypeEnum, IntType};
 use inkwell::values::{
 use inkwell::values::{
-    ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
-    PointerValue,
+    ArrayValue, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue,
 };
 };
 use inkwell::{AddressSpace, IntPredicate};
 use inkwell::{AddressSpace, IntPredicate};
 use num_traits::ToPrimitive;
 use num_traits::ToPrimitive;
@@ -1350,11 +1349,11 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
     ) {
     ) {
         let address = address.unwrap();
         let address = address.unwrap();
 
 
+        contract_args.program_id = Some(address);
         if contract_args.accounts.is_some() {
         if contract_args.accounts.is_some() {
-            contract_args.program_id = Some(address);
             self.build_invoke_signed_c(binary, function, payload, payload_len, contract_args);
             self.build_invoke_signed_c(binary, function, payload, payload_len, contract_args);
         } else {
         } else {
-            self.build_external_call(binary, address, payload, payload_len, contract_args, ns);
+            self.build_external_call(binary, payload, payload_len, contract_args, ns);
         }
         }
     }
     }
 
 
@@ -1662,64 +1661,23 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
-                let key = unsafe {
-                    binary.builder.build_gep(
-                        binary
-                            .module
-                            .get_struct_type("struct.SolParameters")
-                            .unwrap(),
-                        parameters,
-                        &[
-                            binary.context.i32_type().const_int(0, false), // first SolParameters
-                            binary.context.i32_type().const_int(0, false), // first field of SolParameters
-                            binary.context.i32_type().const_int(0, false), // first element of ka[]
-                            binary.context.i32_type().const_int(0, false), // first field of SolAccountInfo (key)
-                        ],
-                        "key",
-                    )
-                };
-
-                let key_pointer = binary.builder.build_load(
-                    binary.address_type(ns).ptr_type(AddressSpace::default()),
-                    key,
-                    "key_pointer",
-                );
-
-                key_pointer.as_basic_value_enum()
-            }
-            codegen::Expression::Builtin {
-                kind: codegen::Builtin::ProgramId,
-                args,
-                ..
-            } => {
-                assert_eq!(args.len(), 0);
-
-                let parameters = self.sol_parameters(binary);
-
                 let sol_pubkey_type = binary.module.get_struct_type("struct.SolPubkey").unwrap();
                 let sol_pubkey_type = binary.module.get_struct_type("struct.SolPubkey").unwrap();
-                let account_id = binary
-                    .builder
-                    .build_load(
-                        sol_pubkey_type.ptr_type(AddressSpace::default()),
-                        binary
-                            .builder
-                            .build_struct_gep(
-                                binary
-                                    .module
-                                    .get_struct_type("struct.SolParameters")
-                                    .unwrap(),
-                                parameters,
-                                4,
-                                "program_id",
-                            )
-                            .unwrap(),
-                        "program_id",
-                    )
-                    .into_pointer_value();
-
-                binary
-                    .builder
-                    .build_load(binary.address_type(ns), account_id, "program_id")
+                binary.builder.build_load(
+                    sol_pubkey_type.ptr_type(AddressSpace::default()),
+                    binary
+                        .builder
+                        .build_struct_gep(
+                            binary
+                                .module
+                                .get_struct_type("struct.SolParameters")
+                                .unwrap(),
+                            parameters,
+                            4,
+                            "program_id",
+                        )
+                        .unwrap(),
+                    "program_id",
+                )
             }
             }
             codegen::Expression::Builtin {
             codegen::Expression::Builtin {
                 kind: codegen::Builtin::Calldata,
                 kind: codegen::Builtin::Calldata,

+ 19 - 4
src/sema/ast.rs

@@ -342,7 +342,7 @@ pub struct Function {
 
 
 /// This struct represents a Solana account. There is no name field, because
 /// This struct represents a Solana account. There is no name field, because
 /// it is stored in a IndexMap<String, SolanaAccount> (see above)
 /// it is stored in a IndexMap<String, SolanaAccount> (see above)
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub struct SolanaAccount {
 pub struct SolanaAccount {
     pub loc: pt::Loc,
     pub loc: pt::Loc,
     pub is_signer: bool,
     pub is_signer: bool,
@@ -1208,7 +1208,6 @@ pub struct CallArgs {
     pub gas: Option<Box<Expression>>,
     pub gas: Option<Box<Expression>>,
     pub salt: Option<Box<Expression>>,
     pub salt: Option<Box<Expression>>,
     pub value: Option<Box<Expression>>,
     pub value: Option<Box<Expression>>,
-    pub address: Option<Box<Expression>>,
     pub accounts: Option<Box<Expression>>,
     pub accounts: Option<Box<Expression>>,
     pub seeds: Option<Box<Expression>>,
     pub seeds: Option<Box<Expression>>,
     pub flags: Option<Box<Expression>>,
     pub flags: Option<Box<Expression>>,
@@ -1263,6 +1262,8 @@ impl Recurse for Expression {
                 | Expression::Not { expr, .. }
                 | Expression::Not { expr, .. }
                 | Expression::BitwiseNot { expr, .. }
                 | Expression::BitwiseNot { expr, .. }
                 | Expression::Negate { expr, .. }
                 | Expression::Negate { expr, .. }
+                | Expression::GetRef { expr, .. }
+                | Expression::NamedMember { array: expr, .. }
                 | Expression::StructMember { expr, .. } => expr.recurse(cx, f),
                 | Expression::StructMember { expr, .. } => expr.recurse(cx, f),
 
 
                 Expression::Add { left, right, .. }
                 Expression::Add { left, right, .. }
@@ -1371,7 +1372,22 @@ impl Recurse for Expression {
                     }
                     }
                 }
                 }
 
 
-                _ => (),
+                Expression::FormatString { format, .. } => {
+                    for (_, arg) in format {
+                        arg.recurse(cx, f);
+                    }
+                }
+
+                Expression::NumberLiteral { .. }
+                | Expression::InterfaceId { .. }
+                | Expression::InternalFunction { .. }
+                | Expression::ConstantVariable { .. }
+                | Expression::StorageVariable { .. }
+                | Expression::Variable { .. }
+                | Expression::RationalNumberLiteral { .. }
+                | Expression::CodeLiteral { .. }
+                | Expression::BytesLiteral { .. }
+                | Expression::BoolLiteral { .. } => (),
             }
             }
         }
         }
     }
     }
@@ -1575,7 +1591,6 @@ pub enum Builtin {
     GasLimit,
     GasLimit,
     BlockNumber,
     BlockNumber,
     Slot,
     Slot,
-    ProgramId,
     Timestamp,
     Timestamp,
     Calldata,
     Calldata,
     Sender,
     Sender,

+ 1 - 12
src/sema/builtin.rs

@@ -309,7 +309,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
 });
 });
 
 
 // A list of all Solidity builtins variables
 // A list of all Solidity builtins variables
-static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
+static BUILTIN_VARIABLE: Lazy<[Prototype; 17]> = Lazy::new(|| {
     [
     [
         Prototype {
         Prototype {
             builtin: Builtin::BlockCoinbase,
             builtin: Builtin::BlockCoinbase,
@@ -366,17 +366,6 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
             doc: "Current slot number",
             doc: "Current slot number",
             constant: false,
             constant: false,
         },
         },
-        Prototype {
-            builtin: Builtin::ProgramId,
-            namespace: Some("tx"),
-            method: vec![],
-            name: "program_id",
-            params: vec![],
-            ret: vec![Type::Address(false)],
-            target: vec![Target::Solana],
-            doc: "Program ID of currently executing program",
-            constant: false,
-        },
         Prototype {
         Prototype {
             builtin: Builtin::Timestamp,
             builtin: Builtin::Timestamp,
             namespace: Some("block"),
             namespace: Some("block"),

+ 3 - 6
src/sema/contracts.rs

@@ -193,13 +193,9 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
     // for every contract, if we have a base which resolved successfully, resolve any constructor args
     // for every contract, if we have a base which resolved successfully, resolve any constructor args
     for contract in contracts {
     for contract in contracts {
         let context = ExprContext {
         let context = ExprContext {
-            function_no: None,
-            contract_no: Some(contract.contract_no),
             file_no,
             file_no,
-            unchecked: false,
-            constant: false,
-            lvalue: false,
-            yul_function: false,
+            contract_no: Some(contract.contract_no),
+            ..Default::default()
         };
         };
 
 
         for base in &contract.base {
         for base in &contract.base {
@@ -231,6 +227,7 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
                 }
                 }
             }
             }
         }
         }
+        context.drop();
     }
     }
 
 
     ns.diagnostics.extend(diagnostics);
     ns.diagnostics.extend(diagnostics);

+ 0 - 3
src/sema/dotgraphviz.rs

@@ -1477,9 +1477,6 @@ impl Dot {
         if let Some(salt) = &call_args.salt {
         if let Some(salt) = &call_args.salt {
             self.add_expression(salt, func, ns, node, String::from("salt"));
             self.add_expression(salt, func, ns, node, String::from("salt"));
         }
         }
-        if let Some(address) = &call_args.address {
-            self.add_expression(address, func, ns, node, String::from("address"));
-        }
         if let Some(accounts) = &call_args.accounts {
         if let Some(accounts) = &call_args.accounts {
             self.add_expression(accounts, func, ns, node, String::from("accounts"));
             self.add_expression(accounts, func, ns, node, String::from("accounts"));
         }
         }

+ 48 - 10
src/sema/expression/constructor.rs

@@ -10,7 +10,7 @@ use crate::sema::unused_variable::used_variable;
 use crate::Target;
 use crate::Target;
 use solang_parser::diagnostics::Diagnostic;
 use solang_parser::diagnostics::Diagnostic;
 use solang_parser::pt;
 use solang_parser::pt;
-use solang_parser::pt::CodeLocation;
+use solang_parser::pt::{CodeLocation, Visibility};
 use std::collections::BTreeMap;
 use std::collections::BTreeMap;
 
 
 /// Resolve an new contract expression with positional arguments
 /// Resolve an new contract expression with positional arguments
@@ -60,15 +60,7 @@ fn constructor(
         return Err(());
         return Err(());
     }
     }
 
 
-    if ns.target == Target::Solana && ns.contracts[no].program_id.is_none() {
-        diagnostics.push(Diagnostic::error(
-            *loc,
-            format!(
-                "in order to instantiate contract '{}', a @program_id is required on contract '{}'",
-                ns.contracts[no].name, ns.contracts[no].name
-            ),
-        ));
-    }
+    solana_constructor_check(loc, no, diagnostics, context, &call_args, ns);
 
 
     // check for circular references
     // check for circular references
     if circular_reference(no, context_contract_no, ns) {
     if circular_reference(no, context_contract_no, ns) {
@@ -268,6 +260,8 @@ pub fn constructor_named_args(
         return Err(());
         return Err(());
     }
     }
 
 
+    solana_constructor_check(loc, no, diagnostics, context, &call_args, ns);
+
     // check for circular references
     // check for circular references
     if circular_reference(no, context_contract_no, ns) {
     if circular_reference(no, context_contract_no, ns) {
         diagnostics.push(Diagnostic::error(
         diagnostics.push(Diagnostic::error(
@@ -580,3 +574,47 @@ pub(super) fn deprecated_constructor_arguments(
 
 
     Ok(())
     Ok(())
 }
 }
+
+/// When calling a constructor on Solana, we must verify it the contract we are instantiating has
+/// a program id annotation and require the accounts call argument if the call is inside a loop.
+fn solana_constructor_check(
+    loc: &pt::Loc,
+    constructor_contract_no: usize,
+    diagnostics: &mut Diagnostics,
+    context: &ExprContext,
+    call_args: &CallArgs,
+    ns: &Namespace,
+) {
+    if ns.target != Target::Solana {
+        return;
+    }
+
+    if ns.contracts[constructor_contract_no].program_id.is_none() {
+        diagnostics.push(Diagnostic::error(
+            *loc,
+            format!(
+                "in order to instantiate contract '{}', a @program_id is required on contract '{}'",
+                ns.contracts[constructor_contract_no].name,
+                ns.contracts[constructor_contract_no].name
+            ),
+        ));
+    }
+
+    if !context.in_a_loop() || call_args.accounts.is_some() {
+        return;
+    }
+
+    if let Some(function_no) = context.function_no {
+        if matches!(
+            ns.functions[function_no].visibility,
+            Visibility::External(_)
+        ) {
+            diagnostics.push(Diagnostic::error(
+                *loc,
+                "the {accounts: ..} call argument is needed since the constructor may be \
+                called multiple times"
+                    .to_string(),
+            ));
+        }
+    }
+}

+ 17 - 73
src/sema/expression/function_call.rs

@@ -2033,45 +2033,6 @@ pub(super) fn parse_call_args(
                     diagnostics,
                     diagnostics,
                 )?));
                 )?));
             }
             }
-            "address" => {
-                if ns.target != Target::Solana {
-                    diagnostics.push(Diagnostic::error(
-                        arg.loc,
-                        format!(
-                            "'address' not permitted for external calls or constructors on {}",
-                            ns.target
-                        ),
-                    ));
-                    return Err(());
-                }
-
-                if external_call {
-                    diagnostics.push(Diagnostic::error(
-                        arg.loc,
-                        "'address' not valid for external calls".to_string(),
-                    ));
-                    return Err(());
-                }
-
-                let ty = Type::Address(false);
-
-                let expr = expression(
-                    &arg.expr,
-                    context,
-                    ns,
-                    symtable,
-                    diagnostics,
-                    ResolveTo::Type(&ty),
-                )?;
-
-                res.address = Some(Box::new(expr.cast(
-                    &arg.expr.loc(),
-                    &ty,
-                    true,
-                    ns,
-                    diagnostics,
-                )?));
-            }
             "salt" => {
             "salt" => {
                 if ns.target == Target::Solana {
                 if ns.target == Target::Solana {
                     diagnostics.push(Diagnostic::error(
                     diagnostics.push(Diagnostic::error(
@@ -2219,40 +2180,23 @@ pub(super) fn parse_call_args(
     }
     }
 
 
     // address is required on solana constructors
     // address is required on solana constructors
-    if ns.target == Target::Solana && !external_call {
-        if res.address.is_none() && res.accounts.is_none() {
-            diagnostics.push(Diagnostic::error(
-                *loc,
-                format!(
-                    "either 'address' or 'accounts' call argument is required on {}",
-                    ns.target
-                ),
-            ));
-            return Err(());
-        } else if res.address.is_some() && res.accounts.is_some() {
-            diagnostics.push(Diagnostic::error(
-                *loc,
-                "'address' and 'accounts' call arguments cannot be used together. \
-                The first address provided on the accounts vector must be the contract's address."
-                    .to_string(),
-            ));
-            return Err(());
-        } else if res.accounts.is_none()
-            && !matches!(
-                ns.functions[context.function_no.unwrap()].visibility,
-                Visibility::External(_)
-            )
-            && !ns.functions[context.function_no.unwrap()].is_constructor()
-        {
-            diagnostics.push(Diagnostic::error(
-                *loc,
-                "accounts are required for calling a contract. You can either provide the \
-                accounts with the {accounts: ...} call argument or change this function's \
-                visibility to external"
-                    .to_string(),
-            ));
-            return Err(());
-        }
+    if ns.target == Target::Solana
+        && !external_call
+        && res.accounts.is_none()
+        && !matches!(
+            ns.functions[context.function_no.unwrap()].visibility,
+            Visibility::External(_)
+        )
+        && !ns.functions[context.function_no.unwrap()].is_constructor()
+    {
+        diagnostics.push(Diagnostic::error(
+            *loc,
+            "accounts are required for calling a contract. You can either provide the \
+            accounts with the {accounts: ...} call argument or change this function's \
+            visibility to external"
+                .to_string(),
+        ));
+        return Err(());
     }
     }
 
 
     Ok(res)
     Ok(res)

+ 4 - 0
src/sema/expression/member_access.rs

@@ -10,8 +10,10 @@ use crate::sema::expression::function_call::function_type;
 use crate::sema::expression::integers::bigint_to_expression;
 use crate::sema::expression::integers::bigint_to_expression;
 use crate::sema::expression::resolve_expression::expression;
 use crate::sema::expression::resolve_expression::expression;
 use crate::sema::expression::{ExprContext, ResolveTo};
 use crate::sema::expression::{ExprContext, ResolveTo};
+use crate::sema::solana_accounts::BuiltinAccounts;
 use crate::sema::symtable::Symtable;
 use crate::sema::symtable::Symtable;
 use crate::sema::unused_variable::{assigned_variable, used_variable};
 use crate::sema::unused_variable::{assigned_variable, used_variable};
+use crate::Target;
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
 use num_traits::{FromPrimitive, One, Zero};
 use num_traits::{FromPrimitive, One, Zero};
 use solang_parser::diagnostics::Diagnostic;
 use solang_parser::diagnostics::Diagnostic;
@@ -246,11 +248,13 @@ pub(super) fn member_access(
                 };
                 };
             } else if matches!(*elem_ty, Type::Struct(StructType::AccountInfo))
             } else if matches!(*elem_ty, Type::Struct(StructType::AccountInfo))
                 && context.function_no.is_some()
                 && context.function_no.is_some()
+                && ns.target == Target::Solana
             {
             {
                 return if ns.functions[context.function_no.unwrap()]
                 return if ns.functions[context.function_no.unwrap()]
                     .solana_accounts
                     .solana_accounts
                     .borrow()
                     .borrow()
                     .contains_key(&id.name)
                     .contains_key(&id.name)
+                    || id.name == BuiltinAccounts::DataAccount
                 {
                 {
                     Ok(Expression::NamedMember {
                     Ok(Expression::NamedMember {
                         loc: *loc,
                         loc: *loc,

+ 20 - 0
src/sema/expression/mod.rs

@@ -66,6 +66,26 @@ pub struct ExprContext {
     pub lvalue: bool,
     pub lvalue: bool,
     /// Are we resolving a yul function (it cannot have external dependencies)
     /// Are we resolving a yul function (it cannot have external dependencies)
     pub yul_function: bool,
     pub yul_function: bool,
+    /// How many loops are we in? (i.e how many nested loops de we have?)
+    pub loop_nesting_level: usize,
+}
+
+impl ExprContext {
+    pub fn enter_loop(&mut self) {
+        self.loop_nesting_level += 1;
+    }
+
+    pub fn exit_loop(&mut self) {
+        self.loop_nesting_level -= 1;
+    }
+
+    pub fn in_a_loop(&self) -> bool {
+        self.loop_nesting_level > 0
+    }
+
+    pub fn drop(&self) {
+        assert_eq!(self.loop_nesting_level, 0);
+    }
 }
 }
 
 
 impl Expression {
 impl Expression {

+ 6 - 0
src/sema/function_annotation.rs

@@ -255,6 +255,12 @@ pub(super) fn function_body_annotations(
                             format!("'{}' is a reserved account name", id.name),
                             format!("'{}' is a reserved account name", id.name),
                         ));
                         ));
                         continue;
                         continue;
+                    } else if id.name.contains(BuiltinAccounts::DataAccount.as_str()) {
+                        diagnostics.push(Diagnostic::error(
+                            id.loc,
+                            "account names that contain 'dataAccount' are reserved".to_string(),
+                        ));
+                        continue;
                     }
                     }
 
 
                     match ns.functions[function_no]
                     match ns.functions[function_no]

+ 102 - 9
src/sema/mutability.rs

@@ -8,6 +8,11 @@ use super::{
     yul::ast::{YulExpression, YulStatement},
     yul::ast::{YulExpression, YulStatement},
     Recurse,
     Recurse,
 };
 };
+use crate::sema::ast::SolanaAccount;
+use crate::sema::solana_accounts::BuiltinAccounts;
+use crate::sema::yul::builtin::YulBuiltInFunction;
+use bitflags::bitflags;
+use solang_parser::pt::Loc;
 use solang_parser::{helpers::CodeLocation, pt};
 use solang_parser::{helpers::CodeLocation, pt};
 
 
 #[derive(PartialEq, PartialOrd)]
 #[derive(PartialEq, PartialOrd)]
@@ -18,6 +23,15 @@ enum Access {
     Value,
     Value,
 }
 }
 
 
+bitflags! {
+    #[derive(PartialEq, Eq, Copy, Clone, Debug)]
+    struct DataAccountUsage: u8 {
+        const NONE = 0;
+        const READ = 1;
+        const WRITE = 2;
+    }
+}
+
 impl Access {
 impl Access {
     fn increase_to(&mut self, other: Access) {
     fn increase_to(&mut self, other: Access) {
         if *self < other {
         if *self < other {
@@ -49,6 +63,7 @@ struct StateCheck<'a> {
     func: &'a Function,
     func: &'a Function,
     modifier: Option<pt::Loc>,
     modifier: Option<pt::Loc>,
     ns: &'a Namespace,
     ns: &'a Namespace,
+    data_account: DataAccountUsage,
 }
 }
 
 
 impl<'a> StateCheck<'a> {
 impl<'a> StateCheck<'a> {
@@ -148,6 +163,7 @@ fn check_mutability(func: &Function, ns: &Namespace) -> Vec<Diagnostic> {
         func,
         func,
         modifier: None,
         modifier: None,
         ns,
         ns,
+        data_account: DataAccountUsage::NONE,
     };
     };
 
 
     for arg in &func.modifiers {
     for arg in &func.modifiers {
@@ -219,6 +235,38 @@ fn check_mutability(func: &Function, ns: &Namespace) -> Vec<Diagnostic> {
         }
         }
     }
     }
 
 
+    if state.data_account != DataAccountUsage::NONE {
+        func.solana_accounts.borrow_mut().insert(
+            BuiltinAccounts::DataAccount.to_string(),
+            SolanaAccount {
+                loc: Loc::Codegen,
+                is_signer: false,
+                is_writer: (state.data_account & DataAccountUsage::WRITE)
+                    == DataAccountUsage::WRITE,
+                generated: true,
+            },
+        );
+    }
+
+    if func.is_constructor() {
+        func.solana_accounts.borrow_mut().insert(
+            BuiltinAccounts::DataAccount.to_string(),
+            SolanaAccount {
+                loc: Loc::Codegen,
+                is_writer: true,
+                /// With a @payer annotation, the account is created on-chain and needs a signer. The client
+                /// provides an address that does not exist yet, so SystemProgram.CreateAccount is called
+                /// on-chain.
+                ///
+                /// However, if a @seed is also provided, the program can sign for the account
+                /// with the seed using program derived address (pda) when SystemProgram.CreateAccount is called,
+                /// so no signer is required from the client.
+                is_signer: func.has_payer_annotation() && !func.has_seed_annotation(),
+                generated: true,
+            },
+        );
+    }
+
     state.diagnostics
     state.diagnostics
 }
 }
 
 
@@ -260,7 +308,10 @@ fn recurse_statements(stmts: &[Statement], ns: &Namespace, state: &mut StateChec
             Statement::Expression(_, _, expr) => {
             Statement::Expression(_, _, expr) => {
                 expr.recurse(state, read_expression);
                 expr.recurse(state, read_expression);
             }
             }
-            Statement::Delete(loc, _, _) => state.write(loc),
+            Statement::Delete(loc, _, _) => {
+                state.data_account |= DataAccountUsage::WRITE;
+                state.write(loc)
+            }
             Statement::Destructure(_, fields, expr) => {
             Statement::Destructure(_, fields, expr) => {
                 // This is either a list or internal/external function call
                 // This is either a list or internal/external function call
                 expr.recurse(state, read_expression);
                 expr.recurse(state, read_expression);
@@ -309,17 +360,31 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
         | Expression::PostIncrement { expr, .. }
         | Expression::PostIncrement { expr, .. }
         | Expression::PostDecrement { expr, .. } => {
         | Expression::PostDecrement { expr, .. } => {
             expr.recurse(state, write_expression);
             expr.recurse(state, write_expression);
+            return false;
         }
         }
         Expression::Assign { left, right, .. } => {
         Expression::Assign { left, right, .. } => {
             right.recurse(state, read_expression);
             right.recurse(state, read_expression);
             left.recurse(state, write_expression);
             left.recurse(state, write_expression);
+            return false;
         }
         }
-        Expression::StorageVariable { loc, .. } => state.read(loc),
         Expression::StorageArrayLength { loc, .. } | Expression::StorageLoad { loc, .. } => {
         Expression::StorageArrayLength { loc, .. } | Expression::StorageLoad { loc, .. } => {
-            state.read(loc)
+            state.data_account |= DataAccountUsage::READ;
+            state.read(loc);
+            return false;
         }
         }
         Expression::Subscript { loc, array_ty, .. } if array_ty.is_contract_storage() => {
         Expression::Subscript { loc, array_ty, .. } if array_ty.is_contract_storage() => {
-            state.read(loc)
+            state.data_account |= DataAccountUsage::READ;
+            state.read(loc);
+            return false;
+        }
+        Expression::Variable { ty, .. } => {
+            if ty.is_contract_storage() {
+                state.data_account |= DataAccountUsage::READ;
+            }
+        }
+        Expression::StorageVariable { loc, .. } => {
+            state.data_account |= DataAccountUsage::READ;
+            state.read(loc);
         }
         }
         Expression::Builtin {
         Expression::Builtin {
             kind: Builtin::FunctionSelector,
             kind: Builtin::FunctionSelector,
@@ -340,7 +405,6 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
                 | Builtin::BlockNumber
                 | Builtin::BlockNumber
                 | Builtin::Slot
                 | Builtin::Slot
                 | Builtin::Timestamp
                 | Builtin::Timestamp
-                | Builtin::ProgramId
                 | Builtin::BlockCoinbase
                 | Builtin::BlockCoinbase
                 | Builtin::BlockDifficulty
                 | Builtin::BlockDifficulty
                 | Builtin::BlockHash
                 | Builtin::BlockHash
@@ -354,6 +418,7 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
                 | Builtin::Accounts,
                 | Builtin::Accounts,
             ..
             ..
         } => state.read(loc),
         } => state.read(loc),
+
         Expression::Builtin {
         Expression::Builtin {
             loc,
             loc,
             kind: Builtin::PayableSend | Builtin::PayableTransfer | Builtin::SelfDestruct,
             kind: Builtin::PayableSend | Builtin::PayableTransfer | Builtin::SelfDestruct,
@@ -377,7 +442,10 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
             kind: Builtin::ArrayPush | Builtin::ArrayPop,
             kind: Builtin::ArrayPush | Builtin::ArrayPop,
             args,
             args,
             ..
             ..
-        } if args[0].ty().is_contract_storage() => state.write(loc),
+        } if args[0].ty().is_contract_storage() => {
+            state.data_account |= DataAccountUsage::WRITE;
+            state.write(loc)
+        }
 
 
         Expression::Constructor { loc, .. } => {
         Expression::Constructor { loc, .. } => {
             state.write(loc);
             state.write(loc);
@@ -398,11 +466,12 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
             CallTy::Static => state.read(loc),
             CallTy::Static => state.read(loc),
             CallTy::Delegate | CallTy::Regular => state.write(loc),
             CallTy::Delegate | CallTy::Regular => state.write(loc),
         },
         },
-        _ => {
-            return true;
+        Expression::NamedMember { name, .. } if name == BuiltinAccounts::DataAccount => {
+            state.data_account |= DataAccountUsage::READ;
         }
         }
+        _ => (),
     }
     }
-    false
+    true
 }
 }
 
 
 fn write_expression(expr: &Expression, state: &mut StateCheck) -> bool {
 fn write_expression(expr: &Expression, state: &mut StateCheck) -> bool {
@@ -412,20 +481,33 @@ fn write_expression(expr: &Expression, state: &mut StateCheck) -> bool {
         }
         }
         | Expression::Subscript { loc, array, .. } => {
         | Expression::Subscript { loc, array, .. } => {
             if array.ty().is_contract_storage() {
             if array.ty().is_contract_storage() {
+                state.data_account |= DataAccountUsage::WRITE;
                 state.write(loc);
                 state.write(loc);
                 return false;
                 return false;
             }
             }
         }
         }
         Expression::Variable { loc, ty, var_no: _ } => {
         Expression::Variable { loc, ty, var_no: _ } => {
             if ty.is_contract_storage() && !expr.ty().is_contract_storage() {
             if ty.is_contract_storage() && !expr.ty().is_contract_storage() {
+                state.data_account |= DataAccountUsage::WRITE;
                 state.write(loc);
                 state.write(loc);
                 return false;
                 return false;
             }
             }
         }
         }
         Expression::StorageVariable { loc, .. } => {
         Expression::StorageVariable { loc, .. } => {
+            state.data_account |= DataAccountUsage::WRITE;
             state.write(loc);
             state.write(loc);
             return false;
             return false;
         }
         }
+        Expression::Builtin {
+            loc,
+            kind: Builtin::Accounts,
+            ..
+        } => {
+            state.write(loc);
+        }
+        Expression::NamedMember { name, .. } if name == BuiltinAccounts::DataAccount => {
+            state.data_account |= DataAccountUsage::WRITE;
+        }
         _ => (),
         _ => (),
     }
     }
 
 
@@ -504,6 +586,17 @@ fn check_expression_mutability_yul(expr: &YulExpression, state: &mut StateCheck)
             } else if builtin_ty.modify_state() {
             } else if builtin_ty.modify_state() {
                 state.write(loc);
                 state.write(loc);
             }
             }
+
+            match builtin_ty {
+                YulBuiltInFunction::SStore => {
+                    state.data_account |= DataAccountUsage::WRITE;
+                }
+                YulBuiltInFunction::SLoad => {
+                    state.data_account |= DataAccountUsage::READ;
+                }
+                _ => (),
+            }
+
             true
             true
         }
         }
         YulExpression::FunctionCall(..) => true,
         YulExpression::FunctionCall(..) => true,

+ 2 - 0
src/sema/namespace.rs

@@ -1498,6 +1498,7 @@ impl Namespace {
             constant: true,
             constant: true,
             lvalue: false,
             lvalue: false,
             yul_function: false,
             yul_function: false,
+            loop_nesting_level: 0,
         };
         };
 
 
         let size_expr = expression(
         let size_expr = expression(
@@ -1508,6 +1509,7 @@ impl Namespace {
             diagnostics,
             diagnostics,
             ResolveTo::Type(&Type::Uint(256)),
             ResolveTo::Type(&Type::Uint(256)),
         )?;
         )?;
+        context.drop();
 
 
         match size_expr.ty() {
         match size_expr.ty() {
             Type::Uint(_) | Type::Int(_) => {}
             Type::Uint(_) | Type::Int(_) => {}

+ 9 - 4
src/sema/solana_accounts.rs

@@ -17,9 +17,9 @@ pub enum BuiltinAccounts {
     InstructionAccount,
     InstructionAccount,
 }
 }
 
 
-impl ToString for BuiltinAccounts {
-    fn to_string(&self) -> String {
-        let str = match self {
+impl BuiltinAccounts {
+    pub fn as_str(&self) -> &'static str {
+        match self {
             BuiltinAccounts::ClockAccount => "clock",
             BuiltinAccounts::ClockAccount => "clock",
             BuiltinAccounts::SystemAccount => "systemProgram",
             BuiltinAccounts::SystemAccount => "systemProgram",
             BuiltinAccounts::AssociatedTokenProgram => "associatedTokenProgram",
             BuiltinAccounts::AssociatedTokenProgram => "associatedTokenProgram",
@@ -27,8 +27,13 @@ impl ToString for BuiltinAccounts {
             BuiltinAccounts::TokenProgramId => "tokenProgram",
             BuiltinAccounts::TokenProgramId => "tokenProgram",
             BuiltinAccounts::DataAccount => "dataAccount",
             BuiltinAccounts::DataAccount => "dataAccount",
             BuiltinAccounts::InstructionAccount => "SysvarInstruction",
             BuiltinAccounts::InstructionAccount => "SysvarInstruction",
-        };
+        }
+    }
+}
 
 
+impl ToString for BuiltinAccounts {
+    fn to_string(&self) -> String {
+        let str = self.as_str();
         str.to_string()
         str.to_string()
     }
     }
 }
 }

+ 15 - 7
src/sema/statements.rs

@@ -41,7 +41,7 @@ pub fn resolve_function_body(
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut loops = LoopScopes::new();
     let mut loops = LoopScopes::new();
     let mut res = Vec::new();
     let mut res = Vec::new();
-    let context = ExprContext {
+    let mut context = ExprContext {
         file_no,
         file_no,
         contract_no,
         contract_no,
         function_no: Some(function_no),
         function_no: Some(function_no),
@@ -49,6 +49,7 @@ pub fn resolve_function_body(
         constant: false,
         constant: false,
         lvalue: false,
         lvalue: false,
         yul_function: false,
         yul_function: false,
+        loop_nesting_level: 0,
     };
     };
 
 
     let mut unresolved_annotation: Vec<UnresolvedAnnotation> = Vec::new();
     let mut unresolved_annotation: Vec<UnresolvedAnnotation> = Vec::new();
@@ -220,6 +221,7 @@ pub fn resolve_function_body(
             }
             }
         }
         }
 
 
+        context.drop();
         ns.diagnostics.extend(diagnostics);
         ns.diagnostics.extend(diagnostics);
         ns.functions[function_no].modifiers = modifiers;
         ns.functions[function_no].modifiers = modifiers;
     }
     }
@@ -285,7 +287,7 @@ pub fn resolve_function_body(
     let reachable = statement(
     let reachable = statement(
         body,
         body,
         &mut res,
         &mut res,
-        &context,
+        &mut context,
         &mut symtable,
         &mut symtable,
         &mut loops,
         &mut loops,
         ns,
         ns,
@@ -342,7 +344,7 @@ pub fn resolve_function_body(
 fn statement(
 fn statement(
     stmt: &pt::Statement,
     stmt: &pt::Statement,
     res: &mut Vec<Statement>,
     res: &mut Vec<Statement>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     loops: &mut LoopScopes,
     loops: &mut LoopScopes,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -432,7 +434,7 @@ fn statement(
                     ));
                     ));
                     return Err(());
                     return Err(());
                 }
                 }
-                reachable = statement(stmt, res, &context, symtable, loops, ns, diagnostics)?;
+                reachable = statement(stmt, res, &mut context, symtable, loops, ns, diagnostics)?;
             }
             }
 
 
             symtable.leave_scope();
             symtable.leave_scope();
@@ -464,6 +466,7 @@ fn statement(
             }
             }
         }
         }
         pt::Statement::While(loc, cond_expr, body) => {
         pt::Statement::While(loc, cond_expr, body) => {
+            context.enter_loop();
             let expr = expression(
             let expr = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -491,10 +494,11 @@ fn statement(
             loops.leave_scope();
             loops.leave_scope();
 
 
             res.push(Statement::While(*loc, true, cond, body_stmts));
             res.push(Statement::While(*loc, true, cond, body_stmts));
-
+            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::DoWhile(loc, body, cond_expr) => {
         pt::Statement::DoWhile(loc, body, cond_expr) => {
+            context.enter_loop();
             let expr = expression(
             let expr = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -522,6 +526,7 @@ fn statement(
             loops.leave_scope();
             loops.leave_scope();
 
 
             res.push(Statement::DoWhile(*loc, true, body_stmts, cond));
             res.push(Statement::DoWhile(*loc, true, body_stmts, cond));
+            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::If(loc, cond_expr, then, else_) => {
         pt::Statement::If(loc, cond_expr, then, else_) => {
@@ -597,6 +602,7 @@ fn statement(
             }
             }
 
 
             loops.new_scope();
             loops.new_scope();
+            context.enter_loop();
 
 
             let mut body = Vec::new();
             let mut body = Vec::new();
 
 
@@ -637,7 +643,7 @@ fn statement(
                 cond: None,
                 cond: None,
                 body,
                 body,
             });
             });
-
+            context.exit_loop();
             Ok(reachable)
             Ok(reachable)
         }
         }
         pt::Statement::For(loc, init_stmt, Some(cond_expr), next_expr, body_stmt) => {
         pt::Statement::For(loc, init_stmt, Some(cond_expr), next_expr, body_stmt) => {
@@ -659,6 +665,7 @@ fn statement(
                 )?;
                 )?;
             }
             }
 
 
+            context.enter_loop();
             let cond = expression(
             let cond = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -716,6 +723,7 @@ fn statement(
                 body,
                 body,
             });
             });
 
 
+            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::Return(loc, None) => {
         pt::Statement::Return(loc, None) => {
@@ -2111,7 +2119,7 @@ fn try_catch(
     expr: &pt::Expression,
     expr: &pt::Expression,
     returns_and_ok: &Option<(Vec<(pt::Loc, Option<pt::Parameter>)>, Box<pt::Statement>)>,
     returns_and_ok: &Option<(Vec<(pt::Loc, Option<pt::Parameter>)>, Box<pt::Statement>)>,
     clause_stmts: &[pt::CatchClause],
     clause_stmts: &[pt::CatchClause],
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     loops: &mut LoopScopes,
     loops: &mut LoopScopes,
     ns: &mut Namespace,
     ns: &mut Namespace,

+ 224 - 0
src/sema/tests/data_account.rs

@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(test)]
+
+use crate::file_resolver::FileResolver;
+use crate::sema::ast::{Namespace, SolanaAccount};
+use crate::{parse_and_resolve, Target};
+use solang_parser::pt::Loc;
+use std::ffi::OsStr;
+
+fn generate_namespace(src: &'static str) -> Namespace {
+    let mut cache = FileResolver::default();
+    cache.set_file_contents("test.sol", src.to_string());
+    parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::Solana)
+}
+
+#[test]
+fn read_account() {
+    let src = r#"
+    import 'solana';
+contract Test {
+    struct myStr {
+        uint64 a;
+        uint64 b;
+    }
+    mapping(string => myStr) mp;
+    int var1;
+    uint[] arr;
+
+    myStr ss1;
+    address add;
+
+    function read1() public view returns (int) {
+        return var1;
+    }
+
+    function read2() public view returns (uint32) {
+        return arr.length;
+    }
+
+    function read3() public view returns (uint[]) {
+        uint[] memory ret = arr;
+        return ret;
+    }
+
+    function read4(uint32 idx) public view returns (uint) {
+        return arr[idx];
+    }
+
+    function read5() public view returns (uint64) {
+        return ss1.a;
+    }
+
+    function read6() public view returns (address) {
+        return tx.accounts.dataAccount.key;
+    }
+
+    function read7() public view returns (address) {
+        AccountMeta[2] meta = [
+            AccountMeta({pubkey: add, is_signer: false, is_writable: true}),
+            AccountMeta({pubkey: address(this), is_signer: false, is_writable: true})
+        ];
+
+        return meta[0].pubkey;
+    }
+}
+    "#;
+    let ns = generate_namespace(src);
+
+    let data_account = SolanaAccount {
+        loc: Loc::Codegen,
+        is_writer: false,
+        is_signer: false,
+        generated: true,
+    };
+
+    let read1 = ns.functions.iter().find(|f| f.name == "read1").unwrap();
+    assert_eq!(
+        *read1.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read2 = ns.functions.iter().find(|f| f.name == "read2").unwrap();
+    assert_eq!(
+        *read2.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read3 = ns.functions.iter().find(|f| f.name == "read3").unwrap();
+    assert_eq!(
+        *read3.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read4 = ns.functions.iter().find(|f| f.name == "read4").unwrap();
+    assert_eq!(
+        *read4.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read5 = ns.functions.iter().find(|f| f.name == "read5").unwrap();
+    assert_eq!(
+        *read5.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read6 = ns.functions.iter().find(|f| f.name == "read6").unwrap();
+    assert_eq!(
+        *read6.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let read7 = ns.functions.iter().find(|f| f.name == "read7").unwrap();
+    assert_eq!(
+        *read7.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+}
+
+#[test]
+fn write_account() {
+    let src = r#"
+    contract Test {
+    struct myStr {
+        uint64 a;
+        uint64 b;
+    }
+    mapping(string => myStr) mp;
+    int var1;
+    uint[] arr;
+
+    myStr ss1;
+
+    function write1(string id) public {
+        delete mp[id];
+    }
+
+    function write2(uint n) public {
+        arr.push(n);
+    }
+
+    function write3() public {
+        arr.pop();
+    }
+
+    function write4(uint num, uint32 idx) public {
+        arr[idx] = num;
+    }
+
+    function write5(uint64 num) public {
+        ss1.b = num;
+    }
+
+    function write6(string id) public {
+        myStr storage ref = mp[id];
+        ref.a = 2;
+        ref.b = 78;
+    }
+
+    function write7(int num) public {
+        var1 = num;
+    }
+
+    function write8(uint64 val) public {
+        tx.accounts.dataAccount.lamports += val;
+    }
+}
+    "#;
+    let ns = generate_namespace(src);
+    let data_account = SolanaAccount {
+        loc: Loc::Codegen,
+        is_writer: true,
+        is_signer: false,
+        generated: true,
+    };
+
+    let write1 = ns.functions.iter().find(|f| f.name == "write1").unwrap();
+    assert_eq!(
+        *write1.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write2 = ns.functions.iter().find(|f| f.name == "write2").unwrap();
+    assert_eq!(
+        *write2.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write3 = ns.functions.iter().find(|f| f.name == "write3").unwrap();
+    assert_eq!(
+        *write3.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write4 = ns.functions.iter().find(|f| f.name == "write4").unwrap();
+    assert_eq!(
+        *write4.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write5 = ns.functions.iter().find(|f| f.name == "write5").unwrap();
+    assert_eq!(
+        *write5.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write6 = ns.functions.iter().find(|f| f.name == "write6").unwrap();
+    assert_eq!(
+        *write6.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write6 = ns.functions.iter().find(|f| f.name == "write6").unwrap();
+    assert_eq!(
+        *write6.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+
+    let write7 = ns.functions.iter().find(|f| f.name == "write7").unwrap();
+    assert_eq!(
+        *write7.solana_accounts.borrow().get("dataAccount").unwrap(),
+        data_account
+    );
+}

+ 6 - 3
src/sema/tests/mod.rs

@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #![cfg(test)]
 #![cfg(test)]
+
+mod data_account;
+
 use crate::sema::ast::{Expression, Parameter, Statement, TryCatch, Type};
 use crate::sema::ast::{Expression, Parameter, Statement, TryCatch, Type};
 use crate::sema::yul::ast::InlineAssembly;
 use crate::sema::yul::ast::InlineAssembly;
 use crate::{parse_and_resolve, sema::ast, FileResolver, Target};
 use crate::{parse_and_resolve, sema::ast, FileResolver, Target};
@@ -452,8 +455,8 @@ contract aborting {
 }
 }
 
 
 contract runner {
 contract runner {
-    function test(address a) external pure {
-        aborting abort = new aborting{address: a}();
+    function test() external pure {
+        aborting abort = new aborting();
 
 
         try abort.abort() returns (int32 a, bool b) {
         try abort.abort() returns (int32 a, bool b) {
             // call succeeded; return values are in a and b
             // call succeeded; return values are in a and b
@@ -606,7 +609,7 @@ contract Child {
     assert_eq!(errors.len(), 1);
     assert_eq!(errors.len(), 1);
     assert_eq!(
     assert_eq!(
         errors[0].message,
         errors[0].message,
-        "either 'address' or 'accounts' call argument is required on Solana"
+        "accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external"
     );
     );
 }
 }
 
 

+ 0 - 3
src/sema/unused_variable.rs

@@ -272,9 +272,6 @@ fn check_call_args(ns: &mut Namespace, call_args: &CallArgs, symtable: &mut Symt
     if let Some(value) = &call_args.value {
     if let Some(value) = &call_args.value {
         used_variable(ns, value.as_ref(), symtable);
         used_variable(ns, value.as_ref(), symtable);
     }
     }
-    if let Some(address) = &call_args.address {
-        used_variable(ns, address.as_ref(), symtable);
-    }
     if let Some(accounts) = &call_args.accounts {
     if let Some(accounts) = &call_args.accounts {
         used_variable(ns, accounts.as_ref(), symtable);
         used_variable(ns, accounts.as_ref(), symtable);
     }
     }

+ 3 - 5
src/sema/variables.rs

@@ -326,6 +326,7 @@ pub fn variable_decl<'a>(
                 constant,
                 constant,
                 lvalue: false,
                 lvalue: false,
                 yul_function: false,
                 yul_function: false,
+                loop_nesting_level: 0,
             };
             };
             match expression(
             match expression(
                 initializer,
                 initializer,
@@ -782,12 +783,8 @@ pub fn resolve_initializers(
 
 
         let context = ExprContext {
         let context = ExprContext {
             file_no,
             file_no,
-            unchecked: false,
             contract_no: Some(*contract_no),
             contract_no: Some(*contract_no),
-            function_no: None,
-            constant: false,
-            lvalue: false,
-            yul_function: false,
+            ..Default::default()
         };
         };
 
 
         if let Ok(res) = expression(
         if let Ok(res) = expression(
@@ -803,6 +800,7 @@ pub fn resolve_initializers(
                 ns.contracts[*contract_no].variables[*var_no].initializer = Some(res);
                 ns.contracts[*contract_no].variables[*var_no].initializer = Some(res);
             }
             }
         }
         }
+        context.drop();
     }
     }
 
 
     ns.diagnostics.extend(diagnostics);
     ns.diagnostics.extend(diagnostics);

+ 12 - 81
src/sema/yul/tests/expression.rs

@@ -23,15 +23,7 @@ use std::sync::Arc;
 
 
 #[test]
 #[test]
 fn resolve_bool_literal() {
 fn resolve_bool_literal() {
-    let ctx = ExprContext {
-        file_no: 0,
-        contract_no: None,
-        function_no: None,
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -71,15 +63,7 @@ fn resolve_bool_literal() {
 
 
 #[test]
 #[test]
 fn resolve_number_literal() {
 fn resolve_number_literal() {
-    let ctx = ExprContext {
-        file_no: 0,
-        contract_no: None,
-        function_no: None,
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -133,15 +117,7 @@ fn resolve_number_literal() {
 
 
 #[test]
 #[test]
 fn resolve_hex_number_literal() {
 fn resolve_hex_number_literal() {
-    let ctx = ExprContext {
-        file_no: 0,
-        contract_no: None,
-        function_no: None,
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -184,15 +160,7 @@ fn resolve_hex_number_literal() {
 
 
 #[test]
 #[test]
 fn resolve_hex_string_literal() {
 fn resolve_hex_string_literal() {
-    let ctx = ExprContext {
-        file_no: 0,
-        contract_no: None,
-        function_no: None,
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -255,15 +223,7 @@ fn resolve_hex_string_literal() {
 
 
 #[test]
 #[test]
 fn resolve_string_literal() {
 fn resolve_string_literal() {
-    let ctx = ExprContext {
-        file_no: 0,
-        contract_no: None,
-        function_no: None,
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -292,15 +252,7 @@ fn resolve_string_literal() {
 
 
 #[test]
 #[test]
 fn resolve_variable_local() {
 fn resolve_variable_local() {
-    let context = ExprContext {
-        file_no: 0,
-        contract_no: Some(0),
-        function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     let mut ns = Namespace::new(Target::EVM);
     let mut ns = Namespace::new(Target::EVM);
@@ -378,6 +330,7 @@ fn resolve_variable_contract() {
         constant: false,
         constant: false,
         lvalue: false,
         lvalue: false,
         yul_function: false,
         yul_function: false,
+        loop_nesting_level: 0,
     };
     };
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
@@ -530,15 +483,7 @@ fn resolve_variable_contract() {
 
 
 #[test]
 #[test]
 fn function_call() {
 fn function_call() {
-    let context = ExprContext {
-        file_no: 0,
-        contract_no: Some(0),
-        function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     function_table.new_scope();
     function_table.new_scope();
@@ -691,15 +636,7 @@ fn function_call() {
 
 
 #[test]
 #[test]
 fn check_arguments() {
 fn check_arguments() {
-    let context = ExprContext {
-        file_no: 0,
-        contract_no: Some(0),
-        function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     function_table.new_scope();
     function_table.new_scope();
@@ -840,7 +777,9 @@ fn test_member_access() {
         constant: false,
         constant: false,
         lvalue: false,
         lvalue: false,
         yul_function: false,
         yul_function: false,
+        loop_nesting_level: 0,
     };
     };
+
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     let mut ns = Namespace::new(Target::EVM);
     let mut ns = Namespace::new(Target::EVM);
@@ -938,15 +877,7 @@ fn test_check_types() {
         0,
         0,
     );
     );
 
 
-    let context = ExprContext {
-        file_no: 0,
-        contract_no: Some(0),
-        function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-    };
+    let context = ExprContext::default();
 
 
     let mut ns = Namespace::new(Target::EVM);
     let mut ns = Namespace::new(Target::EVM);
     let mut contract = ast::Contract::new("test", ContractTy::Contract(loc), vec![], loc);
     let mut contract = ast::Contract::new("test", ContractTy::Contract(loc), vec![], loc);

+ 7 - 53
stdlib/solana.c

@@ -60,8 +60,8 @@ uint64_t sol_invoke_signed_c(const SolInstruction *instruction, const SolAccount
 
 
 // Calls an external function when 'program_id' is NULL or
 // Calls an external function when 'program_id' is NULL or
 // creates a new contract and calls its constructor.
 // creates a new contract and calls its constructor.
-uint64_t external_call(uint8_t *input, uint32_t input_len, SolPubkey *address, SolPubkey *program_id,
-                       const SolSignerSeeds *seeds, int seeds_len, SolParameters *params)
+uint64_t external_call(uint8_t *input, uint32_t input_len, SolPubkey *program_id, const SolSignerSeeds *seeds,
+                       int seeds_len, SolParameters *params)
 {
 {
     SolAccountMeta metas[10];
     SolAccountMeta metas[10];
     SolInstruction instruction = {
     SolInstruction instruction = {
@@ -72,62 +72,16 @@ uint64_t external_call(uint8_t *input, uint32_t input_len, SolPubkey *address, S
         .data_len = input_len,
         .data_len = input_len,
     };
     };
 
 
-    int meta_no = 1;
-    int new_address_idx = -1;
-
+    // When the '{accounts: ...}' call argument is missing, we pass on all the accounts in the transaction.
     for (int account_no = 0; account_no < params->ka_num; account_no++)
     for (int account_no = 0; account_no < params->ka_num; account_no++)
     {
     {
         SolAccountInfo *acc = &params->ka[account_no];
         SolAccountInfo *acc = &params->ka[account_no];
-
-        // The address for the new contract should go first. Note that there
-        // may be duplicate entries, the order of those does not matter.
-        if (new_address_idx < 0 && SolPubkey_same(address, acc->key))
-        {
-            metas[0].pubkey = acc->key;
-            metas[0].is_writable = acc->is_writable;
-            metas[0].is_signer = acc->is_signer;
-            new_address_idx = account_no;
-        }
-        else
-        {
-            metas[meta_no].pubkey = acc->key;
-            metas[meta_no].is_writable = acc->is_writable;
-            metas[meta_no].is_signer = acc->is_signer;
-            meta_no += 1;
-        }
+        metas[account_no].pubkey = acc->key;
+        metas[account_no].is_writable = acc->is_writable;
+        metas[account_no].is_signer = acc->is_signer;
     }
     }
 
 
-    // If the program_id is null, we are dealing with an external call
-    if (!program_id)
-    {
-        if (new_address_idx < 0)
-        {
-            sol_log("call to account not in transaction");
-            sol_panic();
-
-            return ERROR_INVALID_ACCOUNT_DATA;
-        }
-        else
-        {
-            instruction.program_id = params->ka[new_address_idx].owner;
-            return sol_invoke_signed_c(&instruction, params->ka, params->ka_num, NULL, 0);
-        }
-    }
-    else
-    {
-        // This is a constructor call
-        if (new_address_idx < 0)
-        {
-            sol_log("new account needed");
-            sol_panic();
-
-            return ERROR_NEW_ACCOUNT_NEEDED;
-        }
-        else
-        {
-            return sol_invoke_signed_c(&instruction, params->ka, params->ka_num, seeds, seeds_len);
-        }
-    }
+    return sol_invoke_signed_c(&instruction, params->ka, params->ka_num, seeds, seeds_len);
 }
 }
 
 
 uint64_t *sol_account_lamport(uint8_t *address, SolParameters *params)
 uint64_t *sol_account_lamport(uint8_t *address, SolParameters *params)

+ 3 - 3
tests/codegen_testcases/solidity/constructor_with_metas.sol

@@ -10,8 +10,8 @@ contract creator {
             AccountMeta({pubkey: child, is_signer: false, is_writable: false}),
             AccountMeta({pubkey: child, is_signer: false, is_writable: false}),
             AccountMeta({pubkey: payer, is_signer: true, is_writable: true})
             AccountMeta({pubkey: payer, is_signer: true, is_writable: true})
         ];
         ];
-        // CHECK: constructor(no: 4) salt: value: gas:uint64 0 address: seeds: Child encoded buffer: %abi_encoded.temp.17 accounts: %metas
-        c = new Child{accounts: metas}(payer);
+        // CHECK: constructor(no: 4) salt: value: gas:uint64 0 address:address 0xadde28d6c5697771bb24a668136224c7aac8e8ba974c2881484973b2e762fb74 seeds: Child encoded buffer: %abi_encoded.temp.15 accounts: %metas
+        c = new Child{accounts: metas}();
 
 
         c.say_hello();
         c.say_hello();
     }
     }
@@ -21,7 +21,7 @@ contract creator {
 contract Child {
 contract Child {
     @payer(payer)
     @payer(payer)
     @space(511 + 7)
     @space(511 + 7)
-    constructor(address payer) {
+    constructor() {
         print("In child constructor");
         print("In child constructor");
     }
     }
 
 

+ 3 - 3
tests/codegen_testcases/solidity/solana_bump.sol

@@ -9,7 +9,7 @@ contract C1 {
     }
     }
     // BEGIN-CHECK: solang_dispatch
     // BEGIN-CHECK: solang_dispatch
     // 25 must be the last seed in the call.
     // 25 must be the last seed in the call.
-    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.14 value:uint64 0 gas:uint64 0 accounts:%metas.temp.11 seeds:[1] [ [2] [ bytes(%my_seed), bytes(bytes from:bytes1 (bytes1 25)) ] ] contract|function:_ flags:
+    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.15 value:uint64 0 gas:uint64 0 accounts:%metas.temp.11 seeds:[1] [ [2] [ bytes(%my_seed), bytes(bytes from:bytes1 (bytes1 25)) ] ] contract|function:_ flags:
 }
 }
 
 
 contract C2 {
 contract C2 {
@@ -23,7 +23,7 @@ contract C2 {
     }
     }
     // BEGIN-CHECK: solang_dispatch
     // BEGIN-CHECK: solang_dispatch
     // 12 must be the last seed in the call.
     // 12 must be the last seed in the call.
-    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.25 value:uint64 0 gas:uint64 0 accounts:%metas.temp.22 seeds:[1] [ [4] [ (alloc slice bytes1 uint32 5 "apple"), (alloc slice bytes1 uint32 9 "pine_tree"), bytes(%my_seed), bytes(bytes from:bytes1 (bytes1 12)) ] ] contract|function:_ flags:
+    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.27 value:uint64 0 gas:uint64 0 accounts:%metas.temp.23 seeds:[1] [ [4] [ (alloc slice bytes1 uint32 5 "apple"), (alloc slice bytes1 uint32 9 "pine_tree"), bytes(%my_seed), bytes(bytes from:bytes1 (bytes1 12)) ] ] contract|function:_ flags:
 }
 }
 
 
 contract C3 {
 contract C3 {
@@ -36,5 +36,5 @@ contract C3 {
     }
     }
     // BEGIN-CHECK: solang_dispatch
     // BEGIN-CHECK: solang_dispatch
     // bp must be the last seed in the call
     // bp must be the last seed in the call
-    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.37 value:uint64 0 gas:uint64 0 accounts:%metas.temp.34 seeds:[1] [ [4] [ (alloc slice bytes1 uint32 9 "pineapple"), (alloc slice bytes1 uint32 7 "avocado"), bytes(%my_seed), bytes(bytes from:bytes1 (%bp)) ] ] contract|function:_ flags:
+    // CHECK: external call::regular address:address 0x0 payload:%instruction.temp.40 value:uint64 0 gas:uint64 0 accounts:%metas.temp.36 seeds:[1] [ [4] [ (alloc slice bytes1 uint32 9 "pineapple"), (alloc slice bytes1 uint32 7 "avocado"), bytes(%my_seed), bytes(bytes from:bytes1 (%bp)) ] ] contract|function:_ flags:
 }
 }

+ 9 - 8
tests/codegen_testcases/solidity/solana_payer_account.sol

@@ -3,13 +3,13 @@
 @program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
 @program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
 contract Builder {
 contract Builder {
     Built other;
     Built other;
-    // BEGIN-CHECK: Builder::Builder::function::build_this__address
-    function build_this(address addr) external {
-        // CHECK: constructor(no: 4) salt: value: gas:uint64 0 address: seeds: Built encoded buffer: %abi_encoded.temp.18 accounts: [3] [ struct { (deref (arg #0), true, false }, struct { (load (struct (subscript struct AccountInfo[] (builtin Accounts ())[uint32 1]) field 0)), true, true }, struct { (deref address 0x0, false, false } ]
-        other = new Built{address: addr}("my_seed");
+    // BEGIN-CHECK: Builder::Builder::function::build_this
+    function build_this() external {
+        // CHECK: constructor(no: 4) salt: value: gas:uint64 0 address:address 0x69be884fd55a2306354c305323cc6b7ce91768be33d32a021155ef608806bcb seeds: Built encoded buffer: %abi_encoded.temp.18 accounts: [3] [ struct { (load (struct (subscript struct AccountInfo[] (builtin Accounts ())[uint32 2]) field 0)), true, false }, struct { (load (struct (subscript struct AccountInfo[] (builtin Accounts ())[uint32 1]) field 0)), true, true }, struct { (load (struct (subscript struct AccountInfo[] (builtin Accounts ())[uint32 4]) field 0)), false, false } ]
+        other = new Built("my_seed");
     }
     }
 
 
-    function call_that() public pure {
+    function call_that() public view {
         other.say_this("Hold up! I'm calling!");
         other.say_this("Hold up! I'm calling!");
     }
     }
 }
 }
@@ -21,9 +21,10 @@ contract Built {
     @payer(payer_account)
     @payer(payer_account)
     constructor(@seed bytes my_seed) {}
     constructor(@seed bytes my_seed) {}
     // BEGIN-CHECK: solang_dispatch
     // BEGIN-CHECK: solang_dispatch
-    // CHECK: ty:struct AccountInfo %temp.11 = (subscript struct AccountInfo[] (builtin Accounts ())[uint32 1])
-	// CHECK: ty:struct AccountMeta[2] %metas.temp.10 = [2] [ struct { (load (struct %temp.11 field 0)), true, true }, struct { (builtin GetAddress ()), true, true } ]
-	
+    // CHECK: ty:struct AccountInfo %temp.10 = (subscript struct AccountInfo[] (builtin Accounts ())[uint32 1])
+	// CHECK: ty:struct AccountInfo %temp.11 = (subscript struct AccountInfo[] (builtin Accounts ())[uint32 0])
+	// CHECK: ty:struct AccountMeta[2] %metas.temp.9 = [2] [ struct { (load (struct %temp.10 field 0)), true, true }, struct { (load (struct %temp.11 field 0)), true, true } ]
+
     // The account metas should have the proper index in the AccountInfo array: 1
     // The account metas should have the proper index in the AccountInfo array: 1
 
 
     function say_this(string text) public pure {
     function say_this(string text) public pure {

+ 1 - 1
tests/codegen_testcases/solidity/unused_variable_elimination.sol

@@ -214,7 +214,7 @@ contract c3 {
     }
     }
 
 
     // BEGIN-CHECK: c3::function::test18
     // BEGIN-CHECK: c3::function::test18
-    function test18(address payable addr) public returns (bool) {
+    function test18(address payable addr) public payable returns (bool) {
         bool p;
         bool p;
         p = false || addr.send(msg.value);
         p = false || addr.send(msg.value);
         // CHECK: value transfer address
         // CHECK: value transfer address

+ 1 - 1
tests/contract_testcases/solana/account_meta.sol

@@ -18,5 +18,5 @@ contract spl {
 }
 }
 
 
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
-// warning: 4:2-47: function can be declared 'pure'
+// warning: 4:2-47: function can be declared 'view'
 // warning: 9:2-56: function can be declared 'pure'
 // warning: 9:2-56: function can be declared 'pure'

+ 123 - 0
tests/contract_testcases/solana/accounts/constructor_in_loop.sol

@@ -0,0 +1,123 @@
+contract foo {
+    X a;
+    Y ay;
+
+    function contruct() external {
+        a = new X({varia: 2, varb: 5});
+    }
+
+	function test1() external returns (uint) {
+        // This is allowed
+        uint j = a.vara(1, 2);
+		for (uint i = 0; i < 64; i++) {
+			j += a.vara(i, j);
+		}
+        return j;
+	}
+
+    function test2() external returns (uint) {
+        uint j = 3;
+		for (uint i = 0; i < 64; i++) {
+			a = new X(i, j);
+		}
+        return j;
+	}
+
+    function test3() external returns (uint) {
+        uint j = 3;
+        uint n=0;
+		for (uint i = 0; i < 64; i++) {
+			n += i;
+		}
+        a = new X(n, j);
+        return j;
+	}
+
+    function test4(uint v1, string v2) external {
+        ay = new Y({b: v2, a: v1});
+    }
+
+    function test5() external returns (uint) {
+        uint j = 3;
+        uint i=0;
+		while (i < 64) {
+			a = new X(i, j);
+            i++;
+		}
+        return j;
+	}
+
+    function test6() external returns (uint) {
+        uint j = 3;
+        uint i=0;
+		while (i < 64) {
+            i++;
+		}
+        a = new X(i, j);
+        return j;
+	}
+
+    function test7() external returns (uint) {
+        uint j = 3;
+        uint i=0;
+		do {
+			a = new X(i, j);
+            i++;
+		} while (i < 64);
+        return j;
+    }
+
+    function test8() external returns (uint) {
+        uint j = 3;
+        uint i=0;
+		do {
+            i++;
+		} while (i < 64);
+        a = new X(i, j);
+        return j;
+    }
+
+    function test9() external returns (uint) {
+        uint j=9;
+        uint n=0;
+        while (j<90) {
+            j++;
+            for(uint i=0; i<80; i++) {
+                n +=i;
+            }
+            a = new X(j, n);
+        }
+
+        return j;
+    }
+}
+
+@program_id("Foo5mMfYo5RhRcWa4NZ2bwFn4Kdhe8rNK5jchxsKrivA")
+contract X {
+    uint a;
+    uint b;
+    constructor(uint varia, uint varb) {
+        a = varia;
+        b = varb;
+    }
+
+    function vara(uint g, uint h) public view returns (uint) {
+        return g + h + a + b;
+    } 
+}
+
+contract Y {
+    uint za;
+    string zv;
+    constructor(uint a, string b) {
+        za = a;
+        zv = b;
+    }
+}
+
+// ---- Expect: diagnostics ----
+// error: 21:8-19: the {accounts: ..} call argument is needed since the constructor may be called multiple times
+// error: 37:14-35: in order to instantiate contract 'Y', a @program_id is required on contract 'Y'
+// error: 44:8-19: the {accounts: ..} call argument is needed since the constructor may be called multiple times
+// error: 64:8-19: the {accounts: ..} call argument is needed since the constructor may be called multiple times
+// error: 88:17-28: the {accounts: ..} call argument is needed since the constructor may be called multiple times

+ 26 - 0
tests/contract_testcases/solana/accounts/data_account.sol

@@ -0,0 +1,26 @@
+contract FooFoo {
+    @payer(dataAccount)
+    constructor() {
+
+    }
+}
+
+contract FooBar {
+    @payer(my_dataAccount)
+    constructor() {
+
+    }
+}
+
+contract BarFoo {
+    @payer(otherdataAccount)
+    constructor() {
+        
+    }
+}
+
+
+// ---- Expect: diagnostics ----
+// error: 2:12-23: 'dataAccount' is a reserved account name
+// error: 9:12-26: account names that contain 'dataAccount' are reserved
+// error: 16:12-28: account names that contain 'dataAccount' are reserved

+ 8 - 0
tests/contract_testcases/solana/accounts/data_account_visibility.sol

@@ -0,0 +1,8 @@
+contract Foo {
+    function addr_account() public pure returns (address) {
+        return tx.accounts.dataAccount.key;
+    }
+}
+
+// ---- Expect: diagnostics ----
+// error: 3:16-27: function declared 'pure' but this expression reads from state

+ 51 - 0
tests/contract_testcases/solana/accounts/double_calls.sol

@@ -0,0 +1,51 @@
+contract adult {
+    hatchling hh;
+    function test() external {
+        hatchling h1 = new hatchling("luna");
+        hatchling h2 = new hatchling("sol");
+    }
+
+    function create(string id) external {
+        hh = new hatchling(id);
+    }
+
+    function call2() external {
+        hh.call_me("id");
+        hh.call_me("not_id");
+    }
+
+    function create2(string id2) external {
+        hh = new hatchling(id2);
+        hh.call_me(id2);
+    }
+}
+
+
+@program_id("5kQ3iJ43gHNDjqmSAtE1vDu18CiSAfNbRe4v5uoobh3U")
+contract hatchling {
+    string name;
+
+    constructor(string id) payable {
+        require(id != "", "name must be provided");
+        name = id;
+    }
+
+    function call_me(string name2) view external {
+        if (name != name2) {
+                print("This is not my name");
+        } else {
+                print("Have I heard my name?");
+        }
+    }
+}
+
+// ---- Expect: diagnostics ----
+// warning: 4:19-21: local variable 'h1' is unused
+// warning: 5:19-21: local variable 'h2' is unused
+// error: 5:24-44: contract 'hatchling' is called more than once in this function, so automatic account collection cannot happen. Please, provide the necessary accounts using the {accounts:..} call argument
+// 	note 4:24-45: other call
+// warning: 12:5-30: function can be declared 'view'
+// error: 14:9-29: contract 'hatchling' is called more than once in this function, so automatic account collection cannot happen. Please, provide the necessary accounts using the {accounts:..} call argument
+// 	note 13:9-25: other call
+// error: 19:9-24: contract 'hatchling' is called more than once in this function, so automatic account collection cannot happen. Please, provide the necessary accounts using the {accounts:..} call argument
+// 	note 18:14-32: other call

+ 1 - 1
tests/contract_testcases/solana/address_cast.sol

@@ -3,7 +3,7 @@ contract c {
 		// We have code that cast address type to ref address
 		// We have code that cast address type to ref address
 		// in fn sema::cast(). Ensure that this does not cause
 		// in fn sema::cast(). Ensure that this does not cause
 		// address values to be assignable.
 		// address values to be assignable.
-		address(0) = tx.program_id;
+		address(0) = address(this);
 	}
 	}
 }
 }
 
 

+ 2 - 2
tests/contract_testcases/solana/annotations/account_name_collision.sol

@@ -3,8 +3,8 @@ contract Builder {
     BeingBuilt other;
     BeingBuilt other;
     
     
     @payer(payer_account)
     @payer(payer_account)
-    constructor(address addr) {
-        other = new BeingBuilt{address: addr}("abc");
+    constructor() {
+        other = new BeingBuilt("abc");
     }
     }
 }
 }
 
 

+ 9 - 4
tests/contract_testcases/solana/annotations/constructor_external_function.sol

@@ -9,13 +9,17 @@ contract Bar {
     Foo public foo;
     Foo public foo;
 
 
     function external_create_foo(address addr) external {
     function external_create_foo(address addr) external {
-        // This is allowed
+        // This not is allowed
         foo = new Foo{address: addr}();
         foo = new Foo{address: addr}();
     }
     }
 
 
-    function create_foo(address new_address) public {
+    function create_foo() public {
         // This is not allowed
         // This is not allowed
-        foo = new Foo{address: new_address}();
+        foo = new Foo();
+    }
+
+    function this_is_allowed() external {
+        foo = new Foo();
     }
     }
 
 
     function call_foo() public pure {
     function call_foo() public pure {
@@ -24,4 +28,5 @@ contract Bar {
 }
 }
 
 
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
-// error: 18:15-46: accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external
+// error: 13:23-36: 'address' not a valid call parameter
+// error: 18:15-24: accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external

+ 1 - 1
tests/contract_testcases/solana/call/call_args_three_ways.sol

@@ -20,7 +20,7 @@ contract D {
 }
 }
 
 
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
-// error: 4:9-28: either 'address' or 'accounts' call argument is required on Solana
+// error: 4:9-28: accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external
 // error: 4:16-24: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer
 // error: 4:16-24: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer
 // error: 10:10-18: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer
 // error: 10:10-18: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer
 // error: 11:12-20: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer
 // error: 11:12-20: Solana Cross Program Invocation (CPI) cannot transfer native value. See https://solang.readthedocs.io/en/latest/language/functions.html#value_transfer

+ 1 - 1
tests/contract_testcases/solana/expressions/contract_no_init.sol

@@ -15,4 +15,4 @@
             }
             }
         }
         }
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
-// error: 11:25-36: either 'address' or 'accounts' call argument is required on Solana
+// error: 11:25-36: accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external

+ 2 - 2
tests/contract_testcases/solana/mapping_deletion.sol

@@ -19,7 +19,7 @@ contract DeleteTest {
     mapping(uint => savedTest) example2;
     mapping(uint => savedTest) example2;
 
 
     function addData() public  {
     function addData() public  {
-        data_struct dt = data_struct({addr1: address(this), addr2: tx.program_id});
+        data_struct dt = data_struct({addr1: address(this), addr2: tx.accounts.dataAccount.key});
         uint id = 1;
         uint id = 1;
         example[id] = dt;
         example[id] = dt;
         savedTest tt = new savedTest(4);
         savedTest tt = new savedTest(4);
@@ -39,4 +39,4 @@ contract DeleteTest {
 
 
 }
 }
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
-// error: 25:24-40: either 'address' or 'accounts' call argument is required on Solana
+// error: 25:24-40: accounts are required for calling a contract. You can either provide the accounts with the {accounts: ...} call argument or change this function's visibility to external

+ 2 - 1
tests/contract_testcases/solana/yul/yul_switch.sol

@@ -1,6 +1,6 @@
 contract testTypes {
 contract testTypes {
     uint256 b;
     uint256 b;
-    function testAsm(uint128[] calldata vl) public pure returns (uint256) {
+    function testAsm(uint128[] calldata vl) public view returns (uint256) {
         uint256 y = 0;
         uint256 y = 0;
         assembly {
         assembly {
             switch vl.length
             switch vl.length
@@ -17,3 +17,4 @@ contract testTypes {
     }
     }
 } 
 } 
 // ---- Expect: diagnostics ----
 // ---- Expect: diagnostics ----
+// warning: 3:5-74: function declared 'view' can be declared 'pure'

+ 21 - 0
tests/imports_testcases/Dummy.json

@@ -0,0 +1,21 @@
+{
+  "version": "0.0.1",
+  "name": "Dummy",
+  "docs": [
+    "notice: This is a dummy contract to test stuff like redundant (and unneeded)\nimportmaps"
+  ],
+  "instructions": [
+    {
+      "name": "new",
+      "accounts": [
+        {
+          "name": "dataAccount",
+          "isMut": true,
+          "isSigner": false,
+          "isOptional": false
+        }
+      ],
+      "args": []
+    }
+  ]
+}

+ 1 - 1
tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol

@@ -17,7 +17,7 @@ contract c {
         for (uint32 i = 0; i < tx.accounts.length; i++) {
         for (uint32 i = 0; i < tx.accounts.length; i++) {
             AccountInfo ai = tx.accounts[i];
             AccountInfo ai = tx.accounts[i];
 
 
-            if (ai.key == address(this)) {
+            if (ai.key == tx.accounts.dataAccount.key) {
                 return (ai.data.readUint32LE(1), ai.data.length);
                 return (ai.data.readUint32LE(1), ai.data.length);
             }
             }
         }
         }

+ 1 - 1
tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol

@@ -9,7 +9,7 @@ contract foo {
     function test2() public returns (bytes) {
     function test2() public returns (bytes) {
         bytes bs = new bytes(34);
         bytes bs = new bytes(34);
         bs.writeUint16LE(0x4142, 0);
         bs.writeUint16LE(0x4142, 0);
-        bs.writeAddress(tx.program_id, 2);
+        bs.writeAddress(address(this), 2);
         return bs;
         return bs;
     }
     }
 
 

+ 1 - 1
tests/polkadot_tests/calls.rs

@@ -295,7 +295,7 @@ fn try_catch_external_calls() {
                 return c.get_a();
                 return c.get_a();
             }
             }
 
 
-            function test() public pure returns (int32) {
+            function test() public returns (int32) {
                 try c.go_bang() returns (int32 l) {
                 try c.go_bang() returns (int32 l) {
                     print("try call success");
                     print("try call success");
                     return 8000;
                     return 8000;

+ 1 - 1
tests/polkadot_tests/contracts.rs

@@ -205,7 +205,7 @@ fn issue666() {
                 _flipper = _flipperContract;
                 _flipper = _flipperContract;
             }
             }
 
 
-            function superFlip () pure public {
+            function superFlip () view public {
                 _flipper.flip();
                 _flipper.flip();
             }
             }
         }"#,
         }"#,

+ 1 - 1
tests/polkadot_tests/yul.rs

@@ -63,7 +63,7 @@ contract testing  {
         }
         }
     }
     }
 
 
-    function calldata_vec(uint256 input, uint32[] calldata vec) public pure returns (uint256 ret) {
+    function calldata_vec(uint256 input, uint32[] calldata vec) public view returns (uint256 ret) {
         assembly {
         assembly {
             vec.offset := add(input, 7)
             vec.offset := add(input, 7)
             input := 9
             input := 9

+ 7 - 1
tests/solana.rs

@@ -1667,7 +1667,7 @@ impl<'a, 'b> VmFunction<'a, 'b> {
                             accounts
                             accounts
                                 .get(account.name.as_str())
                                 .get(account.name.as_str())
                                 .cloned()
                                 .cloned()
-                                .expect("an account is missing"),
+                                .unwrap_or_else(|| panic!("account '{}' is missing", account.name)),
                         ),
                         ),
                         is_writable: account.is_mut,
                         is_writable: account.is_mut,
                         is_signer: account.is_signer,
                         is_signer: account.is_signer,
@@ -1677,6 +1677,12 @@ impl<'a, 'b> VmFunction<'a, 'b> {
             }
             }
         }
         }
 
 
+        assert_eq!(
+            accounts.len(),
+            metas.len(),
+            "Number of accounts does not match IDL"
+        );
+
         self.accounts = metas;
         self.accounts = metas;
         self
         self
     }
     }

+ 5 - 15
tests/solana_tests/abi.rs

@@ -51,21 +51,13 @@ fn packed() {
         .accounts(vec![("dataAccount", account)])
         .accounts(vec![("dataAccount", account)])
         .call();
         .call();
 
 
-    vm.function("test")
-        .accounts(vec![("dataAccount", account)])
-        .call();
+    vm.function("test").call();
 
 
-    vm.function("test2")
-        .accounts(vec![("dataAccount", account)])
-        .call();
+    vm.function("test2").call();
 
 
-    vm.function("test3")
-        .accounts(vec![("dataAccount", account)])
-        .call();
+    vm.function("test3").call();
 
 
-    vm.function("test4")
-        .accounts(vec![("dataAccount", account)])
-        .call();
+    vm.function("test4").call();
 }
 }
 
 
 #[test]
 #[test]
@@ -85,9 +77,7 @@ fn inherited() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    vm.function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    vm.function("test").call();
 
 
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"

+ 2 - 13
tests/solana_tests/abi_decode.rs

@@ -125,14 +125,13 @@ fn decode_address() {
         .call();
         .call();
 
 
     let input = Data {
     let input = Data {
-        address: data_account,
-        this: data_account,
+        address: vm.stack[0].id,
+        this: vm.stack[0].id,
     };
     };
     let encoded = input.try_to_vec().unwrap();
     let encoded = input.try_to_vec().unwrap();
     let _ = vm
     let _ = vm
         .function("testAddress")
         .function("testAddress")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -169,7 +168,6 @@ fn string_and_bytes() {
     let _ = vm
     let _ = vm
         .function("testStringAndBytes")
         .function("testStringAndBytes")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -633,7 +631,6 @@ fn arrays() {
     let _ = vm
     let _ = vm
         .function("decodeComplex")
         .function("decodeComplex")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
     let input = Input2 {
     let input = Input2 {
@@ -643,7 +640,6 @@ fn arrays() {
     let _ = vm
     let _ = vm
         .function("dynamicArray")
         .function("dynamicArray")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
     let input = Input3 {
     let input = Input3 {
@@ -653,7 +649,6 @@ fn arrays() {
     let _ = vm
     let _ = vm
         .function("decodeMultiDim")
         .function("decodeMultiDim")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -920,7 +915,6 @@ fn external_function() {
     let returns = vm
     let returns = vm
         .function("testExternalFunction")
         .function("testExternalFunction")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -969,7 +963,6 @@ fn bytes_arrays() {
     let _ = vm
     let _ = vm
         .function("testByteArrays")
         .function("testByteArrays")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -1008,7 +1001,6 @@ fn different_types() {
     let _ = vm
     let _ = vm
         .function("testByteArrays")
         .function("testByteArrays")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -1042,7 +1034,6 @@ fn more_elements() {
     let _ = vm
     let _ = vm
         .function("wrongNumber")
         .function("wrongNumber")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -1149,7 +1140,6 @@ fn longer_buffer() {
     let _ = vm
     let _ = vm
         .function("testLongerBuffer")
         .function("testLongerBuffer")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 
@@ -1188,7 +1178,6 @@ fn longer_buffer_array() {
     let _ = vm
     let _ = vm
         .function("testLongerBuffer")
         .function("testLongerBuffer")
         .arguments(&[BorshToken::Bytes(encoded)])
         .arguments(&[BorshToken::Bytes(encoded)])
-        .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 }
 }
 
 

+ 8 - 24
tests/solana_tests/abi_encode.rs

@@ -115,15 +115,11 @@ contract Testing {
     vm.function("new")
     vm.function("new")
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
-    let returns = vm
-        .function("getThis")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("getThis").call().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
-    assert_eq!(decoded.address, data_account);
-    assert_eq!(decoded.this, data_account);
+    assert_eq!(decoded.address, vm.stack[0].id);
+    assert_eq!(decoded.this, vm.stack[0].id);
 }
 }
 
 
 #[test]
 #[test]
@@ -526,11 +522,7 @@ fn struct_in_array() {
     assert_eq!(decoded.item_3[0], NoPadStruct { a: 1, b: 2 });
     assert_eq!(decoded.item_3[0], NoPadStruct { a: 1, b: 2 });
     assert_eq!(decoded.item_3[1], NoPadStruct { a: 3, b: 4 });
     assert_eq!(decoded.item_3[1], NoPadStruct { a: 3, b: 4 });
 
 
-    let returns = vm
-        .function("primitiveDynamicArray")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("primitiveDynamicArray").call().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let decoded = Res3::try_from_slice(&encoded).unwrap();
     let decoded = Res3::try_from_slice(&encoded).unwrap();
 
 
@@ -626,11 +618,7 @@ fn arrays() {
     assert_eq!(decoded.vec_1[1], 5523);
     assert_eq!(decoded.vec_1[1], 5523);
     assert_eq!(decoded.vec_1[2], -89);
     assert_eq!(decoded.vec_1[2], -89);
 
 
-    let returns = vm
-        .function("encodeComplex")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("encodeComplex").call().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
 
@@ -911,12 +899,7 @@ fn external_function() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("doThat")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap()
-        .unwrap_tuple();
+    let returns = vm.function("doThat").call().unwrap().unwrap_tuple();
     let encoded = returns[2].clone().into_bytes().unwrap();
     let encoded = returns[2].clone().into_bytes().unwrap();
     let decoded = Res::try_from_slice(&encoded).unwrap();
     let decoded = Res::try_from_slice(&encoded).unwrap();
 
 
@@ -1032,11 +1015,12 @@ contract caller {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
+    let caller_program_id = vm.stack[0].id;
     let returns = vm
     let returns = vm
         .function("do_call")
         .function("do_call")
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
+            ("caller_programId", caller_program_id),
         ])
         ])
         .call()
         .call()
         .unwrap()
         .unwrap()

+ 11 - 19
tests/solana_tests/accessor.rs

@@ -183,11 +183,7 @@ fn constant() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("z")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("z").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -209,11 +205,7 @@ fn constant() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("z")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("z").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -235,11 +227,7 @@ fn constant() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("z")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("z").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -254,6 +242,7 @@ fn constant() {
 fn struct_accessor() {
 fn struct_accessor() {
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"
+        import 'solana';
         contract C {
         contract C {
             struct E {
             struct E {
                 bytes4 b4;
                 bytes4 b4;
@@ -274,13 +263,16 @@ fn struct_accessor() {
             }
             }
 
 
             function f() public view {
             function f() public view {
-                (int64 a1, bool b, E memory c) = this.a();
+                AccountMeta[1] meta = [
+                    AccountMeta({pubkey: tx.accounts.dataAccount.key, is_writable: false, is_signer: false})
+                ];
+                (int64 a1, bool b, E memory c) = this.a{accounts: meta}();
                 require(a1 == -63 && !b && c.b4 == "nuff", "a");
                 require(a1 == -63 && !b && c.b4 == "nuff", "a");
-                (a1, b, c) = this.s(99);
+                (a1, b, c) = this.s{accounts: meta}(99);
                 require(a1 == 65535 && b && c.b4 == "naff", "b");
                 require(a1 == 65535 && b && c.b4 == "naff", "b");
-                (a1, b, c) = this.m(1023413412);
+                (a1, b, c) = this.m{accounts: meta}(1023413412);
                 require(a1 == 414243 && b && c.b4 == "niff", "c");
                 require(a1 == 414243 && b && c.b4 == "niff", "c");
-                c.b4 = this.e();
+                c.b4 = this.e{accounts: meta}();
                 require(a1 == 414243 && b && c.b4 == "cons", "E");
                 require(a1 == 414243 && b && c.b4 == "cons", "E");
             }
             }
         }"#,
         }"#,

+ 8 - 34
tests/solana_tests/account_info.rs

@@ -45,7 +45,6 @@ fn lamports() {
     let returns = vm
     let returns = vm
         .function("test")
         .function("test")
         .arguments(&[BorshToken::Address(acc)])
         .arguments(&[BorshToken::Address(acc)])
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(acc),
             pubkey: Pubkey(acc),
             is_writable: true,
             is_writable: true,
@@ -70,15 +69,7 @@ fn owner() {
         import 'solana';
         import 'solana';
         contract c {
         contract c {
             function test() public payable returns (address) {
             function test() public payable returns (address) {
-                for (uint32 i = 0; i < tx.accounts.length; i++) {
-                    AccountInfo ai = tx.accounts[i];
-
-                    if (ai.key == address(this)) {
-                        return ai.owner;
-                    }
-                }
-
-                revert("account not found");
+                return tx.accounts.dataAccount.owner;
             }
             }
         }"#,
         }"#,
     );
     );
@@ -106,27 +97,12 @@ fn data() {
         import 'solana';
         import 'solana';
         contract c {
         contract c {
             function test(uint32 index) public payable returns (uint8) {
             function test(uint32 index) public payable returns (uint8) {
-                for (uint32 i = 0; i < tx.accounts.length; i++) {
-                    AccountInfo ai = tx.accounts[i];
-
-                    if (ai.key == address(this)) {
-                        return ai.data[index];
-                    }
-                }
-
-                revert("account not found");
+                return tx.accounts.dataAccount.data[index];
             }
             }
 
 
             function test2() public payable returns (uint32, uint32) {
             function test2() public payable returns (uint32, uint32) {
-                for (uint32 i = 0; i < tx.accounts.length; i++) {
-                    AccountInfo ai = tx.accounts[i];
-
-                    if (ai.key == address(this)) {
-                        return (ai.data.readUint32LE(1), ai.data.length);
-                    }
-                }
-
-                revert("account not found");
+                AccountInfo ai = tx.accounts.dataAccount;
+                return (ai.data.readUint32LE(1), ai.data.length);
             }
             }
         }"#,
         }"#,
     );
     );
@@ -193,9 +169,9 @@ import 'solana';
 
 
 contract starter {
 contract starter {
     function createNewAccount(uint64 lamport1, uint64 lamport2, uint64 lamport3) public {
     function createNewAccount(uint64 lamport1, uint64 lamport2, uint64 lamport3) public {
-        AccountInfo acc1 = tx.accounts[1];
-        AccountInfo acc2 = tx.accounts[2];
-        AccountInfo acc3 = tx.accounts[3];
+        AccountInfo acc1 = tx.accounts[0];
+        AccountInfo acc2 = tx.accounts[1];
+        AccountInfo acc3 = tx.accounts[2];
 
 
         acc1.lamports -= lamport1;
         acc1.lamports -= lamport1;
         acc2.lamports = lamport2;
         acc2.lamports = lamport2;
@@ -272,7 +248,6 @@ contract starter {
                 value: BigInt::from(9u8),
                 value: BigInt::from(9u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&metas)
         .remaining_accounts(&metas)
         .call();
         .call();
 
 
@@ -289,7 +264,7 @@ import 'solana';
 
 
 contract C {
 contract C {
 	function test() external {
 	function test() external {
-		AccountInfo ai = tx.accounts[1];
+		AccountInfo ai = tx.accounts[0];
 		ai.data[0] = 0xca;
 		ai.data[0] = 0xca;
 		ai.data[1] = 0xff;
 		ai.data[1] = 0xff;
 		ai.data[2] = 0xee;
 		ai.data[2] = 0xee;
@@ -315,7 +290,6 @@ contract C {
     );
     );
 
 
     vm.function("test")
     vm.function("test")
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(other_account),
             pubkey: Pubkey(other_account),
             is_writable: true,
             is_writable: true,

+ 3 - 5
tests/solana_tests/account_serialization.rs

@@ -13,7 +13,7 @@ fn deserialize_duplicate_account() {
         assert(tx.accounts[1].is_signer == tx.accounts[2].is_signer);
         assert(tx.accounts[1].is_signer == tx.accounts[2].is_signer);
         assert(tx.accounts[1].is_writable == tx.accounts[2].is_writable);
         assert(tx.accounts[1].is_writable == tx.accounts[2].is_writable);
 
 
-        assert(my_address == tx.program_id);
+        assert(my_address == tx.accounts.dataAccount.key);
     }
     }
 }
 }
         "#,
         "#,
@@ -44,9 +44,8 @@ fn deserialize_duplicate_account() {
         },
         },
     );
     );
 
 
-    let program_id = vm.stack[0].id;
     vm.function("check_deserialization")
     vm.function("check_deserialization")
-        .arguments(&[BorshToken::Address(program_id)])
+        .arguments(&[BorshToken::Address(data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&[
         .remaining_accounts(&[
             AccountMeta {
             AccountMeta {
@@ -71,7 +70,7 @@ fn more_than_10_accounts() {
     function check_deserialization(address my_address) public view {
     function check_deserialization(address my_address) public view {
         // This assertion ensure the padding is correctly added when
         // This assertion ensure the padding is correctly added when
         // deserializing accounts
         // deserializing accounts
-        assert(my_address == tx.program_id);
+        assert(my_address == address(this));
     }
     }
 }
 }
         "#,
         "#,
@@ -119,7 +118,6 @@ fn more_than_10_accounts() {
     let program_id = vm.stack[0].id;
     let program_id = vm.stack[0].id;
     vm.function("check_deserialization")
     vm.function("check_deserialization")
         .arguments(&[BorshToken::Address(program_id)])
         .arguments(&[BorshToken::Address(program_id)])
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&metas)
         .remaining_accounts(&metas)
         .call();
         .call();
 }
 }

+ 17 - 82
tests/solana_tests/arrays.rs

@@ -25,12 +25,7 @@ fn fixed_array() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("get")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap()
-        .unwrap_tuple();
+    let returns = vm.function("get").call().unwrap().unwrap_tuple();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -79,11 +74,7 @@ fn fixed_array() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("get")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("get").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -155,11 +146,7 @@ fn fixed_array() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("get")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("get").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -211,7 +198,6 @@ fn fixed_array() {
             ]),
             ]),
             BorshToken::Bool(true),
             BorshToken::Bool(true),
         ])])
         ])])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -287,7 +273,6 @@ fn dynamic_array_fixed_elements() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -300,12 +285,7 @@ fn dynamic_array_fixed_elements() {
     );
     );
 
 
     // test that the abi encoder can handle fixed arrays
     // test that the abi encoder can handle fixed arrays
-    let returns = vm
-        .function("set")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap()
-        .unwrap_tuple();
+    let returns = vm.function("set").call().unwrap().unwrap_tuple();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -391,7 +371,6 @@ fn fixed_array_dynamic_elements() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -403,12 +382,7 @@ fn fixed_array_dynamic_elements() {
         }
         }
     );
     );
 
 
-    let returns = vm
-        .function("set")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap()
-        .unwrap_tuple();
+    let returns = vm.function("set").call().unwrap().unwrap_tuple();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -486,7 +460,6 @@ fn dynamic_array_dynamic_elements() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -498,12 +471,7 @@ fn dynamic_array_dynamic_elements() {
         }
         }
     );
     );
 
 
-    let returns = vm
-        .function("set")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap()
-        .unwrap_tuple();
+    let returns = vm.function("set").call().unwrap().unwrap_tuple();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -1754,10 +1722,7 @@ fn dynamic_array_push() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -1783,10 +1748,7 @@ fn dynamic_array_push() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -1817,10 +1779,7 @@ fn dynamic_array_push() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -1847,10 +1806,7 @@ fn dynamic_array_push() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     // push() returns a reference to the thing
     // push() returns a reference to the thing
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
@@ -1881,10 +1837,7 @@ fn dynamic_array_push() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 }
 }
 
 
 #[test]
 #[test]
@@ -1913,10 +1866,7 @@ fn dynamic_array_pop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -1942,10 +1892,7 @@ fn dynamic_array_pop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -1978,10 +1925,7 @@ fn dynamic_array_pop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -2008,10 +1952,7 @@ fn dynamic_array_pop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 }
 }
 
 
 #[test]
 #[test]
@@ -2113,10 +2054,7 @@ fn dynamic_array_push_pop_loop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -2160,10 +2098,7 @@ fn dynamic_array_push_pop_loop() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 }
 }
 
 
 #[test]
 #[test]

+ 144 - 72
tests/solana_tests/balance.rs

@@ -34,12 +34,18 @@ fn get_balance() {
     let returns = vm
     let returns = vm
         .function("test")
         .function("test")
         .arguments(&[BorshToken::Address(new)])
         .arguments(&[BorshToken::Address(new)])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: false,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: false,
+                is_writable: false,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: false,
+            },
+        ])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -88,12 +94,18 @@ fn send_fails() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -140,12 +152,18 @@ fn send_succeeds() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -195,12 +213,18 @@ fn send_overflows() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -254,12 +278,18 @@ fn transfer_succeeds() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call();
         .call();
 
 
     assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
     assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
@@ -305,12 +335,18 @@ fn transfer_fails_not_enough() {
                 value: BigInt::from(104u8),
                 value: BigInt::from(104u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .must_fail();
         .must_fail();
     assert!(res.is_err());
     assert!(res.is_err());
 
 
@@ -326,12 +362,18 @@ fn transfer_fails_not_enough() {
                 value: BigInt::from(103u8),
                 value: BigInt::from(103u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call();
         .call();
 
 
     assert_eq!(vm.account_data[&data_account].lamports, 0);
     assert_eq!(vm.account_data[&data_account].lamports, 0);
@@ -378,12 +420,18 @@ fn transfer_fails_overflow() {
                 value: BigInt::from(104u8),
                 value: BigInt::from(104u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_writable: false,
-            is_signer: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_writable: false,
+                is_signer: true,
+            },
+        ])
         .must_fail();
         .must_fail();
     assert!(res.is_err());
     assert!(res.is_err());
 
 
@@ -399,12 +447,18 @@ fn transfer_fails_overflow() {
                 value: BigInt::from(100u8),
                 value: BigInt::from(100u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_writable: false,
-            is_signer: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_writable: false,
+                is_signer: true,
+            },
+        ])
         .call();
         .call();
 
 
     assert_eq!(vm.account_data[&new].lamports, u64::MAX);
     assert_eq!(vm.account_data[&new].lamports, u64::MAX);
@@ -486,12 +540,18 @@ fn value_overflows() {
                 value: BigInt::from(u64::MAX as u128 + 1),
                 value: BigInt::from(u64::MAX as u128 + 1),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .must_fail();
         .must_fail();
     assert_eq!(res.unwrap(), 4294967296);
     assert_eq!(res.unwrap(), 4294967296);
 
 
@@ -504,12 +564,18 @@ fn value_overflows() {
                 value: BigInt::from(u128::MAX),
                 value: BigInt::from(u128::MAX),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .must_fail();
         .must_fail();
 
 
     assert_eq!(res.unwrap(), 4294967296);
     assert_eq!(res.unwrap(), 4294967296);
@@ -523,12 +589,18 @@ fn value_overflows() {
                 value: BigInt::from(102u8),
                 value: BigInt::from(102u8),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(new),
-            is_signer: false,
-            is_writable: true,
-        }])
+        .remaining_accounts(&[
+            AccountMeta {
+                pubkey: Pubkey(data_account),
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: Pubkey(new),
+                is_signer: false,
+                is_writable: true,
+            },
+        ])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 

+ 9 - 38
tests/solana_tests/builtin.rs

@@ -25,7 +25,7 @@ fn builtins() {
                 return msg.sig;
                 return msg.sig;
             }
             }
             function prog() public returns (address) {
             function prog() public returns (address) {
-                return tx.program_id;
+                return address(this);
             }
             }
         }"#,
         }"#,
     );
     );
@@ -43,10 +43,7 @@ fn builtins() {
     .unwrap();
     .unwrap();
     let returns = vm
     let returns = vm
         .function("mr_now")
         .function("mr_now")
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("clock", clock_account),
-        ])
+        .accounts(vec![("clock", clock_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -60,10 +57,7 @@ fn builtins() {
 
 
     let returns = vm
     let returns = vm
         .function("mr_slot")
         .function("mr_slot")
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("clock", clock_account),
-        ])
+        .accounts(vec![("clock", clock_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -77,10 +71,7 @@ fn builtins() {
 
 
     let returns = vm
     let returns = vm
         .function("mr_blocknumber")
         .function("mr_blocknumber")
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("clock", clock_account),
-        ])
+        .accounts(vec![("clock", clock_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -98,7 +89,6 @@ fn builtins() {
             width: 32,
             width: 32,
             value: BigInt::from(0xdeadcafeu32),
             value: BigInt::from(0xdeadcafeu32),
         }])
         }])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -111,11 +101,7 @@ fn builtins() {
         BorshToken::Bytes(hex::decode("a73fcaa3b216e85afecaadde").unwrap())
         BorshToken::Bytes(hex::decode("a73fcaa3b216e85afecaadde").unwrap())
     );
     );
 
 
-    let returns = vm
-        .function("sig")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("sig").call().unwrap();
 
 
     if let Some(v) = returns.clone().into_fixed_bytes() {
     if let Some(v) = returns.clone().into_fixed_bytes() {
         println!("{}", hex::encode(v));
         println!("{}", hex::encode(v));
@@ -126,11 +112,7 @@ fn builtins() {
         BorshToken::uint8_fixed_array(hex::decode("4b22101a3c98d6cb").unwrap())
         BorshToken::uint8_fixed_array(hex::decode("4b22101a3c98d6cb").unwrap())
     );
     );
 
 
-    let returns = vm
-        .function("prog")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("prog").call().unwrap();
 
 
     assert_eq!(returns, BorshToken::Address(vm.stack[0].id));
     assert_eq!(returns, BorshToken::Address(vm.stack[0].id));
 }
 }
@@ -179,10 +161,7 @@ fn pda() {
     let returns = vm
     let returns = vm
         .function("create_pda")
         .function("create_pda")
         .arguments(&[BorshToken::Bool(true)])
         .arguments(&[BorshToken::Bool(true)])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -198,10 +177,7 @@ fn pda() {
     let returns = vm
     let returns = vm
         .function("create_pda")
         .function("create_pda")
         .arguments(&[BorshToken::Bool(false)])
         .arguments(&[BorshToken::Bool(false)])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -220,10 +196,7 @@ fn pda() {
             BorshToken::Bytes(b"Talking".to_vec()),
             BorshToken::Bytes(b"Talking".to_vec()),
             BorshToken::Bytes(b"Squirrels".to_vec()),
             BorshToken::Bytes(b"Squirrels".to_vec()),
         ])
         ])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -239,7 +212,6 @@ fn pda() {
     let returns = vm
     let returns = vm
         .function("create_pda2_bump")
         .function("create_pda2_bump")
         .arguments(&[BorshToken::Bool(true)])
         .arguments(&[BorshToken::Bool(true)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -258,7 +230,6 @@ fn pda() {
     let returns = vm
     let returns = vm
         .function("create_pda2_bump")
         .function("create_pda2_bump")
         .arguments(&[BorshToken::Bool(false)])
         .arguments(&[BorshToken::Bool(false)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();

+ 18 - 40
tests/solana_tests/call.rs

@@ -4,7 +4,7 @@ use crate::{
     build_solidity, create_program_address, AccountMeta, AccountState, BorshToken, Instruction,
     build_solidity, create_program_address, AccountMeta, AccountState, BorshToken, Instruction,
     Pubkey, VirtualMachine,
     Pubkey, VirtualMachine,
 };
 };
-use base58::FromBase58;
+use base58::{FromBase58, ToBase58};
 use num_bigint::BigInt;
 use num_bigint::BigInt;
 use num_traits::One;
 use num_traits::One;
 
 
@@ -36,7 +36,6 @@ fn simple_external_call() {
         .call();
         .call();
 
 
     vm.function("test_bar")
     vm.function("test_bar")
-        .accounts(vec![("dataAccount", bar1_account)])
         .arguments(&[BorshToken::String(String::from("yo"))])
         .arguments(&[BorshToken::String(String::from("yo"))])
         .call();
         .call();
 
 
@@ -52,7 +51,6 @@ fn simple_external_call() {
         .call();
         .call();
 
 
     vm.function("test_bar")
     vm.function("test_bar")
-        .accounts(vec![("dataAccount", bar0_account)])
         .arguments(&[BorshToken::String(String::from("uncle beau"))])
         .arguments(&[BorshToken::String(String::from("uncle beau"))])
         .call();
         .call();
 
 
@@ -62,7 +60,7 @@ fn simple_external_call() {
 
 
     vm.function("test_other")
     vm.function("test_other")
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", bar0_account),
+            ("bar1_programId", bar1_program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
         .remaining_accounts(&[
         .remaining_accounts(&[
@@ -77,7 +75,7 @@ fn simple_external_call() {
                 is_writable: false,
                 is_writable: false,
             },
             },
         ])
         ])
-        .arguments(&[BorshToken::Address(bar1_account)])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
         .call();
         .call();
 
 
     assert_eq!(vm.logs, "bar1 says: cross contract call");
     assert_eq!(vm.logs, "bar1 says: cross contract call");
@@ -108,7 +106,6 @@ fn external_call_with_returns() {
 
 
     let res = vm
     let res = vm
         .function("test_bar")
         .function("test_bar")
-        .accounts(vec![("dataAccount", bar1_account)])
         .arguments(&[BorshToken::Int {
         .arguments(&[BorshToken::Int {
             width: 64,
             width: 64,
             value: BigInt::from(21),
             value: BigInt::from(21),
@@ -133,9 +130,9 @@ fn external_call_with_returns() {
 
 
     let res = vm
     let res = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(bar1_account)])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", bar0_account),
+            ("bar1_programId", bar1_program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
         .remaining_accounts(&[
         .remaining_accounts(&[
@@ -198,7 +195,6 @@ fn external_raw_call_with_returns() {
             width: 64,
             width: 64,
             value: BigInt::from(21u8),
             value: BigInt::from(21u8),
         }])
         }])
-        .accounts(vec![("dataAccount", bar1_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -219,11 +215,8 @@ fn external_raw_call_with_returns() {
 
 
     let res = vm
     let res = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(bar1_account)])
-        .accounts(vec![
-            ("dataAccount", bar0_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
+        .accounts(vec![("systemProgram", [0; 32])])
         .remaining_accounts(&[
         .remaining_accounts(&[
             AccountMeta {
             AccountMeta {
                 pubkey: Pubkey(bar1_account),
                 pubkey: Pubkey(bar1_account),
@@ -275,10 +268,7 @@ fn call_external_func_type() {
 
 
     let res = vm
     let res = vm
         .function("doTest")
         .function("doTest")
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -338,7 +328,6 @@ fn external_call_with_string_returns() {
             width: 64,
             width: 64,
             value: BigInt::from(22u8),
             value: BigInt::from(22u8),
         }])
         }])
-        .accounts(vec![("dataAccount", bar1_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -353,9 +342,9 @@ fn external_call_with_string_returns() {
 
 
     let res = vm
     let res = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(bar1_account)])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", bar0_account),
+            ("bar1_programId", bar1_program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
         .remaining_accounts(&[
         .remaining_accounts(&[
@@ -376,9 +365,9 @@ fn external_call_with_string_returns() {
     assert_eq!(res, BorshToken::String(String::from("foo:7")));
     assert_eq!(res, BorshToken::String(String::from("foo:7")));
 
 
     vm.function("test_this")
     vm.function("test_this")
-        .arguments(&[BorshToken::Address(bar1_account)])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", bar0_account),
+            ("bar1_programId", bar1_program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
         .remaining_accounts(&[
         .remaining_accounts(&[
@@ -414,7 +403,7 @@ fn encode_call() {
         }
         }
 
 
         contract bar1 {
         contract bar1 {
-            function test_bar(int64 y) public returns (int64) {
+            function test_bar(int64 y) public pure returns (int64) {
                 return 3 + y;
                 return 3 + y;
             }
             }
         }"#,
         }"#,
@@ -432,7 +421,6 @@ fn encode_call() {
             width: 64,
             width: 64,
             value: BigInt::from(21u8),
             value: BigInt::from(21u8),
         }])
         }])
-        .accounts(vec![("dataAccount", bar1_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -451,13 +439,11 @@ fn encode_call() {
         .accounts(vec![("dataAccount", bar0_account)])
         .accounts(vec![("dataAccount", bar0_account)])
         .call();
         .call();
 
 
+    std::println!("bar_acc: {}", bar1_account.to_base58());
     let res = vm
     let res = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(bar1_account)])
-        .accounts(vec![
-            ("dataAccount", bar0_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .arguments(&[BorshToken::Address(bar1_program_id)])
+        .accounts(vec![("systemProgram", [0; 32])])
         .remaining_accounts(&[
         .remaining_accounts(&[
             AccountMeta {
             AccountMeta {
                 pubkey: Pubkey(bar1_account),
                 pubkey: Pubkey(bar1_account),
@@ -677,11 +663,7 @@ fn raw_call_accounts() {
             BorshToken::Address(b"quinquagintaquadringentilliardth".to_owned()),
             BorshToken::Address(b"quinquagintaquadringentilliardth".to_owned()),
             BorshToken::Address(b"quinquagintaquadringentillionths".to_owned()),
             BorshToken::Address(b"quinquagintaquadringentillionths".to_owned()),
         ])
         ])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("tokenProgram", token.0),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("tokenProgram", token.0), ("systemProgram", [0; 32])])
         .call();
         .call();
 }
 }
 
 
@@ -749,10 +731,6 @@ fn pda() {
     vm.call_params_check.insert(token.clone(), test_args);
     vm.call_params_check.insert(token.clone(), test_args);
 
 
     vm.function("test")
     vm.function("test")
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("tokenProgram", token.0),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("tokenProgram", token.0), ("systemProgram", [0; 32])])
         .call();
         .call();
 }
 }

+ 2 - 10
tests/solana_tests/constant.rs

@@ -25,11 +25,7 @@ fn constant() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("f")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("f").call().unwrap();
     assert_eq!(
     assert_eq!(
         returns,
         returns,
         BorshToken::Uint {
         BorshToken::Uint {
@@ -58,11 +54,7 @@ fn constant() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("f")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("f").call().unwrap();
     assert_eq!(
     assert_eq!(
         returns,
         returns,
         BorshToken::Uint {
         BorshToken::Uint {

+ 60 - 87
tests/solana_tests/create_contract.rs

@@ -11,8 +11,8 @@ fn simple_create_contract_no_seed() {
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"
         contract bar0 {
         contract bar0 {
-            function test_other(address foo) external returns (bar1) {
-                bar1 x = new bar1{address: foo}("yo from bar0");
+            function test_other() external returns (bar1) {
+                bar1 x = new bar1("yo from bar0");
 
 
                 return x;
                 return x;
             }
             }
@@ -65,9 +65,9 @@ fn simple_create_contract_no_seed() {
 
 
     let bar1 = vm
     let bar1 = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(acc)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
+            ("bar1_dataAccount", acc),
+            ("bar1_programId", program_id),
             ("payer", payer),
             ("payer", payer),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
@@ -88,21 +88,9 @@ fn simple_create_contract_no_seed() {
     vm.function("call_bar1_at_address")
     vm.function("call_bar1_at_address")
         .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
         .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
+            ("bar1_programId", program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
-        .remaining_accounts(&[
-            AccountMeta {
-                pubkey: Pubkey(acc),
-                is_signer: false,
-                is_writable: false,
-            },
-            AccountMeta {
-                pubkey: Pubkey(program_id),
-                is_writable: false,
-                is_signer: false,
-            },
-        ])
         .call();
         .call();
 
 
     assert_eq!(vm.logs, "Hello xywoleh");
     assert_eq!(vm.logs, "Hello xywoleh");
@@ -113,8 +101,8 @@ fn simple_create_contract() {
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"
         contract bar0 {
         contract bar0 {
-            function test_other(address foo) external returns (bar1) {
-                bar1 x = new bar1{address: foo}("yo from bar0");
+            function test_other() external returns (bar1) {
+                bar1 x = new bar1("yo from bar0");
 
 
                 return x;
                 return x;
             }
             }
@@ -156,17 +144,12 @@ fn simple_create_contract() {
 
 
     let bar1 = vm
     let bar1 = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(seed.0)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
+            ("bar1_dataAccount", seed.0),
+            ("bar1_programId", program_id),
             ("pay", payer),
             ("pay", payer),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
-        .remaining_accounts(&[AccountMeta {
-            pubkey: Pubkey(seed.0),
-            is_signer: false,
-            is_writable: true,
-        }])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -179,21 +162,9 @@ fn simple_create_contract() {
     vm.function("call_bar1_at_address")
     vm.function("call_bar1_at_address")
         .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
         .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
+            ("bar1_programId", program_id),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
-        .remaining_accounts(&[
-            AccountMeta {
-                pubkey: Pubkey(seed.0),
-                is_signer: false,
-                is_writable: false,
-            },
-            AccountMeta {
-                pubkey: Pubkey(program_id),
-                is_writable: false,
-                is_signer: false,
-            },
-        ])
         .call();
         .call();
 
 
     assert_eq!(vm.logs, "Hello xywoleh");
     assert_eq!(vm.logs, "Hello xywoleh");
@@ -309,8 +280,8 @@ fn missing_contract() {
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"
         contract bar0 {
         contract bar0 {
-            function test_other(address foo) external returns (bar1) {
-                bar1 x = new bar1{address: foo}("yo from bar0");
+            function test_other() external returns (bar1) {
+                bar1 x = new bar1("yo from bar0");
 
 
                 return x;
                 return x;
             }
             }
@@ -341,6 +312,7 @@ fn missing_contract() {
     let missing = account_new();
     let missing = account_new();
     vm.logs.clear();
     vm.logs.clear();
     vm.account_data.insert(missing, AccountState::default());
     vm.account_data.insert(missing, AccountState::default());
+
     let program_id: Account = "7vJKRaKLGCNUPuHWdeHCTknkYf3dHXXEZ6ri7dc6ngeV"
     let program_id: Account = "7vJKRaKLGCNUPuHWdeHCTknkYf3dHXXEZ6ri7dc6ngeV"
         .from_base58()
         .from_base58()
         .unwrap()
         .unwrap()
@@ -350,23 +322,11 @@ fn missing_contract() {
     // There is no payer account, so the external call fails.
     // There is no payer account, so the external call fails.
     let _ = vm
     let _ = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(missing)])
         .accounts(vec![
         .accounts(vec![
-            ("dataAccount", data_account),
+            ("bar1_programId", program_id),
+            ("bar1_dataAccount", missing),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])
-        .remaining_accounts(&[
-            AccountMeta {
-                pubkey: Pubkey(missing),
-                is_signer: true,
-                is_writable: false,
-            },
-            AccountMeta {
-                pubkey: Pubkey(program_id),
-                is_writable: false,
-                is_signer: false,
-            },
-        ])
         .must_fail();
         .must_fail();
 }
 }
 
 
@@ -374,10 +334,20 @@ fn missing_contract() {
 fn two_contracts() {
 fn two_contracts() {
     let mut vm = build_solidity(
     let mut vm = build_solidity(
         r#"
         r#"
+        import 'solana';
+
         contract bar0 {
         contract bar0 {
-            function test_other(address a, address b) external returns (bar1) {
-                bar1 x = new bar1{address: a}("yo from bar0");
-                bar1 y = new bar1{address: b}("hi from bar0");
+            function test_other(address a, address b, address payer) external returns (bar1) {
+                AccountMeta[2] bar1_metas = [
+                    AccountMeta({pubkey: a, is_writable: true, is_signer: true}),
+                    AccountMeta({pubkey: payer, is_writable: true, is_signer: true})
+                ];
+                AccountMeta[2] bar2_metas = [
+                    AccountMeta({pubkey: b, is_writable: true, is_signer: true}),
+                    AccountMeta({pubkey: payer, is_writable: true, is_signer: true})
+                ];
+                bar1 x = new bar1{accounts: bar1_metas}("yo from bar0");
+                bar1 y = new bar1{accounts: bar2_metas}("hi from bar0");
 
 
                 return x;
                 return x;
             }
             }
@@ -407,18 +377,19 @@ fn two_contracts() {
     let seed1 = vm.create_pda(&program_id, 5);
     let seed1 = vm.create_pda(&program_id, 5);
     let seed2 = vm.create_pda(&program_id, 5);
     let seed2 = vm.create_pda(&program_id, 5);
     let payer = account_new();
     let payer = account_new();
+
     vm.account_data.insert(seed1.0, AccountState::default());
     vm.account_data.insert(seed1.0, AccountState::default());
     vm.account_data.insert(seed2.0, AccountState::default());
     vm.account_data.insert(seed2.0, AccountState::default());
     vm.account_data.insert(payer, AccountState::default());
     vm.account_data.insert(payer, AccountState::default());
 
 
     let _bar1 = vm
     let _bar1 = vm
         .function("test_other")
         .function("test_other")
-        .arguments(&[BorshToken::Address(seed1.0), BorshToken::Address(seed2.0)])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-            ("payer_account", payer),
+        .arguments(&[
+            BorshToken::Address(seed1.0),
+            BorshToken::Address(seed2.0),
+            BorshToken::Address(payer),
         ])
         ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .remaining_accounts(&[
         .remaining_accounts(&[
             AccountMeta {
             AccountMeta {
                 pubkey: Pubkey(seed1.0),
                 pubkey: Pubkey(seed1.0),
@@ -435,6 +406,11 @@ fn two_contracts() {
                 is_writable: false,
                 is_writable: false,
                 is_signer: false,
                 is_signer: false,
             },
             },
+            AccountMeta {
+                pubkey: Pubkey(payer),
+                is_signer: true,
+                is_writable: true,
+            },
         ])
         ])
         .call();
         .call();
 
 
@@ -507,11 +483,7 @@ fn account_with_space() {
         306
         306
     );
     );
 
 
-    let ret = vm
-        .function("hello")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let ret = vm.function("hello").call().unwrap();
 
 
     assert_eq!(ret, BorshToken::Bool(true));
     assert_eq!(ret, BorshToken::Bool(true));
 }
 }
@@ -552,11 +524,7 @@ fn account_with_seed() {
         511 + 102
         511 + 102
     );
     );
 
 
-    let ret = vm
-        .function("hello")
-        .accounts(vec![("dataAccount", seed.0)])
-        .call()
-        .unwrap();
+    let ret = vm.function("hello").call().unwrap();
 
 
     assert_eq!(ret, BorshToken::Bool(true));
     assert_eq!(ret, BorshToken::Bool(true));
 }
 }
@@ -607,11 +575,7 @@ fn account_with_seed_bump() {
         511 + 102
         511 + 102
     );
     );
 
 
-    let ret = vm
-        .function("hello")
-        .accounts(vec![("dataAccount", address)])
-        .call()
-        .unwrap();
+    let ret = vm.function("hello").call().unwrap();
 
 
     assert_eq!(ret, BorshToken::Bool(true));
     assert_eq!(ret, BorshToken::Bool(true));
 }
 }
@@ -655,11 +619,7 @@ fn account_with_seed_bump_literals() {
         8192
         8192
     );
     );
 
 
-    let ret = vm
-        .function("hello")
-        .accounts(vec![("dataAccount", account.0)])
-        .call()
-        .unwrap();
+    let ret = vm.function("hello").call().unwrap();
 
 
     assert_eq!(ret, BorshToken::Bool(true));
     assert_eq!(ret, BorshToken::Bool(true));
 }
 }
@@ -671,10 +631,9 @@ fn create_child() {
         contract creator {
         contract creator {
             Child public c;
             Child public c;
 
 
-            function create_child(address child) external {
+            function create_child() external {
                 print("Going to create child");
                 print("Going to create child");
-                c = new Child{address: child}();
-
+                c = new Child();
                 c.say_hello();
                 c.say_hello();
             }
             }
         }
         }
@@ -699,6 +658,12 @@ fn create_child() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
+    let child_program_id: Account = "Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT"
+        .from_base58()
+        .unwrap()
+        .try_into()
+        .unwrap();
+
     let payer = account_new();
     let payer = account_new();
     let program_id = vm.stack[0].id;
     let program_id = vm.stack[0].id;
 
 
@@ -707,8 +672,9 @@ fn create_child() {
     vm.account_data.insert(seed.0, AccountState::default());
     vm.account_data.insert(seed.0, AccountState::default());
 
 
     vm.function("create_child")
     vm.function("create_child")
-        .arguments(&[BorshToken::Address(seed.0)])
         .accounts(vec![
         .accounts(vec![
+            ("Child_dataAccount", seed.0),
+            ("Child_programId", child_program_id),
             ("dataAccount", data_account),
             ("dataAccount", data_account),
             ("payer", payer),
             ("payer", payer),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
@@ -774,9 +740,16 @@ contract Child {
     vm.account_data.insert(seed.0, AccountState::default());
     vm.account_data.insert(seed.0, AccountState::default());
     vm.account_data.insert(payer, AccountState::default());
     vm.account_data.insert(payer, AccountState::default());
 
 
+    let child_program_id: Account = "Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT"
+        .from_base58()
+        .unwrap()
+        .try_into()
+        .unwrap();
+
     vm.function("create_child_with_meta")
     vm.function("create_child_with_meta")
         .arguments(&[BorshToken::Address(seed.0), BorshToken::Address(payer)])
         .arguments(&[BorshToken::Address(seed.0), BorshToken::Address(payer)])
         .accounts(vec![
         .accounts(vec![
+            ("Child_programId", child_program_id),
             ("dataAccount", data_account),
             ("dataAccount", data_account),
             ("systemProgram", [0; 32]),
             ("systemProgram", [0; 32]),
         ])
         ])

+ 1 - 9
tests/solana_tests/destructure.rs

@@ -26,7 +26,6 @@ fn conditional_destructure() {
     let returns = vm
     let returns = vm
         .function("f")
         .function("f")
         .arguments(&[BorshToken::Bool(true), BorshToken::Bool(true)])
         .arguments(&[BorshToken::Bool(true), BorshToken::Bool(true)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -48,7 +47,6 @@ fn conditional_destructure() {
     let returns = vm
     let returns = vm
         .function("f")
         .function("f")
         .arguments(&[BorshToken::Bool(true), BorshToken::Bool(false)])
         .arguments(&[BorshToken::Bool(true), BorshToken::Bool(false)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -70,7 +68,6 @@ fn conditional_destructure() {
     let returns = vm
     let returns = vm
         .function("f")
         .function("f")
         .arguments(&[BorshToken::Bool(false), BorshToken::Bool(false)])
         .arguments(&[BorshToken::Bool(false), BorshToken::Bool(false)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -92,7 +89,6 @@ fn conditional_destructure() {
     let returns = vm
     let returns = vm
         .function("f")
         .function("f")
         .arguments(&[BorshToken::Bool(false), BorshToken::Bool(true)])
         .arguments(&[BorshToken::Bool(false), BorshToken::Bool(true)])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -169,11 +165,7 @@ fn casting_destructure() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("f")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("f").call().unwrap();
 
 
     assert_eq!(returns, BorshToken::String(String::from("Hello")));
     assert_eq!(returns, BorshToken::String(String::from("Hello")));
 }
 }

+ 2 - 6
tests/solana_tests/events.rs

@@ -28,9 +28,7 @@ fn simple_event() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    vm.function("go")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    vm.function("go").call();
 
 
     assert_eq!(vm.events.len(), 1);
     assert_eq!(vm.events.len(), 1);
     assert_eq!(vm.events[0].len(), 1);
     assert_eq!(vm.events[0].len(), 1);
@@ -87,9 +85,7 @@ fn less_simple_event() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    vm.function("go")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    vm.function("go").call();
 
 
     assert_eq!(vm.events.len(), 1);
     assert_eq!(vm.events.len(), 1);
     assert_eq!(vm.events[0].len(), 1);
     assert_eq!(vm.events[0].len(), 1);

+ 5 - 26
tests/solana_tests/expressions.rs

@@ -25,11 +25,7 @@ fn interfaceid() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("get")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("get").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
@@ -52,7 +48,7 @@ fn write_buffer() {
             function test2() public returns (bytes) {
             function test2() public returns (bytes) {
                 bytes bs = new bytes(34);
                 bytes bs = new bytes(34);
                 bs.writeUint16LE(0x4142, 0);
                 bs.writeUint16LE(0x4142, 0);
-                bs.writeAddress(tx.program_id, 2);
+                bs.writeAddress(address(this), 2);
                 return bs;
                 return bs;
             }
             }
 
 
@@ -69,32 +65,21 @@ fn write_buffer() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    let returns = vm
-        .function("test1")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("test1").call().unwrap();
 
 
     assert_eq!(
     assert_eq!(
         returns,
         returns,
         BorshToken::Bytes([0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec())
         BorshToken::Bytes([0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec())
     );
     );
 
 
-    let returns = vm
-        .function("test2")
-        .accounts(vec![("dataAccount", data_account)])
-        .call()
-        .unwrap();
+    let returns = vm.function("test2").call().unwrap();
 
 
     let mut buf = vec![0x42u8, 0x41u8];
     let mut buf = vec![0x42u8, 0x41u8];
     buf.extend_from_slice(&vm.stack[0].id);
     buf.extend_from_slice(&vm.stack[0].id);
 
 
     assert_eq!(returns, BorshToken::Bytes(buf));
     assert_eq!(returns, BorshToken::Bytes(buf));
 
 
-    let res = vm
-        .function("test3")
-        .accounts(vec![("dataAccount", data_account)])
-        .must_fail();
+    let res = vm.function("test3").must_fail();
     assert_eq!(res.unwrap(), 4294967296);
     assert_eq!(res.unwrap(), 4294967296);
 }
 }
 
 
@@ -123,7 +108,6 @@ fn read_buffer() {
         .arguments(&[BorshToken::Bytes(
         .arguments(&[BorshToken::Bytes(
             [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(),
             [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(),
         )])
         )])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -147,7 +131,6 @@ fn read_buffer() {
         .arguments(&[BorshToken::Bytes(
         .arguments(&[BorshToken::Bytes(
             [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2].to_vec(),
             [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2].to_vec(),
         )])
         )])
-        .accounts(vec![("dataAccount", data_account)])
         .must_fail();
         .must_fail();
     assert_eq!(res.unwrap(), 4294967296);
     assert_eq!(res.unwrap(), 4294967296);
 
 
@@ -158,7 +141,6 @@ fn read_buffer() {
     let returns = vm
     let returns = vm
         .function("test2")
         .function("test2")
         .arguments(&[BorshToken::Bytes(buf.clone())])
         .arguments(&[BorshToken::Bytes(buf.clone())])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap()
         .unwrap()
         .unwrap_tuple();
         .unwrap_tuple();
@@ -179,7 +161,6 @@ fn read_buffer() {
     let res = vm
     let res = vm
         .function("test2")
         .function("test2")
         .arguments(&[BorshToken::Bytes(buf)])
         .arguments(&[BorshToken::Bytes(buf)])
-        .accounts(vec![("dataAccount", data_account)])
         .must_fail();
         .must_fail();
     assert_eq!(res.unwrap(), 4294967296);
     assert_eq!(res.unwrap(), 4294967296);
 }
 }
@@ -207,7 +188,6 @@ fn bytes_compare() {
     let returns = vm
     let returns = vm
         .function("test1")
         .function("test1")
         .arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
         .arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -216,7 +196,6 @@ fn bytes_compare() {
     let returns = vm
     let returns = vm
         .function("test2")
         .function("test2")
         .arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
         .arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 

+ 6 - 24
tests/solana_tests/hash.rs

@@ -21,10 +21,7 @@ fn constants_hash_tests() {
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
 
 
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -42,10 +39,7 @@ fn constants_hash_tests() {
         .function("new")
         .function("new")
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 
 
     let mut runtime = build_solidity(
     let mut runtime = build_solidity(
         r#"
         r#"
@@ -63,10 +57,7 @@ fn constants_hash_tests() {
         .function("new")
         .function("new")
         .accounts(vec![("dataAccount", data_account)])
         .accounts(vec![("dataAccount", data_account)])
         .call();
         .call();
-    runtime
-        .function("test")
-        .accounts(vec![("dataAccount", data_account)])
-        .call();
+    runtime.function("test").call();
 }
 }
 
 
 #[test]
 #[test]
@@ -90,10 +81,7 @@ fn hash_tests() {
     let hash = runtime
     let hash = runtime
         .function("test")
         .function("test")
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -123,10 +111,7 @@ fn hash_tests() {
     let hash = runtime
     let hash = runtime
         .function("test")
         .function("test")
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -157,10 +142,7 @@ fn hash_tests() {
     let hash = runtime
     let hash = runtime
         .function("test")
         .function("test")
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
         .arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
-        .accounts(vec![
-            ("dataAccount", data_account),
-            ("systemProgram", [0; 32]),
-        ])
+        .accounts(vec![("systemProgram", [0; 32])])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 

+ 0 - 6
tests/solana_tests/math.rs

@@ -56,7 +56,6 @@ fn safe_math() {
                 value: BigInt::from_str("4000000000000000000").unwrap(),
                 value: BigInt::from_str("4000000000000000000").unwrap(),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -80,7 +79,6 @@ fn safe_math() {
                 value: BigInt::from_str("4000000000000000000").unwrap(),
                 value: BigInt::from_str("4000000000000000000").unwrap(),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -104,7 +102,6 @@ fn safe_math() {
                 value: BigInt::from_str("1000000000000000000").unwrap(),
                 value: BigInt::from_str("1000000000000000000").unwrap(),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .call()
         .call()
         .unwrap();
         .unwrap();
 
 
@@ -127,7 +124,6 @@ fn safe_math() {
                 value: BigInt::from_str("400000000000000000000000000000000000000").unwrap(),
                 value: BigInt::from_str("400000000000000000000000000000000000000").unwrap(),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .must_fail();
         .must_fail();
 
 
     vm.function(
     vm.function(
@@ -144,7 +140,6 @@ fn safe_math() {
             },
             },
         ],
         ],
     )
     )
-        .accounts(vec![("dataAccount", data_account)])
         .must_fail();
         .must_fail();
 
 
     vm.function("sub_test")
     vm.function("sub_test")
@@ -158,6 +153,5 @@ fn safe_math() {
                 value: BigInt::from_str("4000000000000000000").unwrap(),
                 value: BigInt::from_str("4000000000000000000").unwrap(),
             },
             },
         ])
         ])
-        .accounts(vec![("dataAccount", data_account)])
         .must_fail();
         .must_fail();
 }
 }

+ 0 - 4
tests/solana_tests/metas.rs

@@ -141,7 +141,6 @@ contract Foo {
     let res = vm
     let res = vm
         .function("token_account")
         .function("token_account")
         .arguments(&[BorshToken::Address(account)])
         .arguments(&[BorshToken::Address(account)])
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(account),
             pubkey: Pubkey(account),
             is_signer: false,
             is_signer: false,
@@ -190,7 +189,6 @@ contract Foo {
     let res = vm
     let res = vm
         .function("token_account")
         .function("token_account")
         .arguments(&[BorshToken::Address(account)])
         .arguments(&[BorshToken::Address(account)])
-        .accounts(vec![("dataAccount", data_account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(account),
             pubkey: Pubkey(account),
             is_signer: false,
             is_signer: false,
@@ -289,7 +287,6 @@ contract Foo {
 
 
     let res = vm
     let res = vm
         .function("mint_account")
         .function("mint_account")
-        .accounts(vec![("dataAccount", data_account)])
         .arguments(&[BorshToken::Address(account)])
         .arguments(&[BorshToken::Address(account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(account),
             pubkey: Pubkey(account),
@@ -327,7 +324,6 @@ contract Foo {
 
 
     let res = vm
     let res = vm
         .function("mint_account")
         .function("mint_account")
-        .accounts(vec![("dataAccount", data_account)])
         .arguments(&[BorshToken::Address(account)])
         .arguments(&[BorshToken::Address(account)])
         .remaining_accounts(&[AccountMeta {
         .remaining_accounts(&[AccountMeta {
             pubkey: Pubkey(account),
             pubkey: Pubkey(account),

Some files were not shown because too many files changed in this diff