diff --git a/Cargo.toml b/Cargo.toml
index ea5b81f19..98cda6185 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,6 +65,7 @@ wasm-opt = { version = "0.112.0", optional = true }
contract-build = { version = "3.0.1", optional = true }
primitive-types = { version = "0.12", features = ["codec"] }
normalize-path = "0.2.1"
+bitflags = "2.3.3"
[dev-dependencies]
num-derive = "0.4"
diff --git a/docs/examples/solana/contract_address.sol b/docs/examples/solana/contract_address.sol
index 01dc96bf4..4626baf93 100644
--- a/docs/examples/solana/contract_address.sol
+++ b/docs/examples/solana/contract_address.sol
@@ -10,6 +10,6 @@ contract hatchling {
contract adult {
function test(address addr) external {
- hatchling h = new hatchling{address: addr}("luna");
+ hatchling h = new hatchling("luna");
}
}
diff --git a/docs/examples/solana/contract_new.sol b/docs/examples/solana/contract_new.sol
deleted file mode 100644
index 8f7f5f78d..000000000
--- a/docs/examples/solana/contract_new.sol
+++ /dev/null
@@ -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));
- }
-}
diff --git a/docs/examples/solana/payer_annotation.sol b/docs/examples/solana/payer_annotation.sol
index 4924d5761..bc6b44b78 100644
--- a/docs/examples/solana/payer_annotation.sol
+++ b/docs/examples/solana/payer_annotation.sol
@@ -3,10 +3,10 @@ import 'solana';
@program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
contract Builder {
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 {
diff --git a/docs/examples/solana/program_id.sol b/docs/examples/solana/program_id.sol
index dfe9da60b..8152d5f87 100644
--- a/docs/examples/solana/program_id.sol
+++ b/docs/examples/solana/program_id.sol
@@ -8,11 +8,11 @@ contract Foo {
contract Bar {
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();
}
}
diff --git a/docs/language/builtins.rst b/docs/language/builtins.rst
index d5c6c5d68..663abdf08 100644
--- a/docs/language/builtins.rst
+++ b/docs/language/builtins.rst
@@ -108,10 +108,6 @@ AccountInfo[] ``tx.accounts``
.. include:: ../examples/solana/accountinfo.sol
:code: solidity
-address ``tx.program_id``
- The address or account of the currently executing program. Only available on
- Solana.
-
``block`` properties
++++++++++++++++++++++
diff --git a/docs/language/contracts.rst b/docs/language/contracts.rst
index 8ae3f39b3..cf8ea4990 100644
--- a/docs/language/contracts.rst
+++ b/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
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
: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
-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,
one needs to instantiate a fixed length array of type ``AccountMeta`` to pass to the call. The array must contain all
diff --git a/docs/language/expressions.rst b/docs/language/expressions.rst
index 9c9878570..1c5e04c94 100644
--- a/docs/language/expressions.rst
+++ b/docs/language/expressions.rst
@@ -124,8 +124,8 @@ this only works with public functions.
.. 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
__________________
diff --git a/docs/language/managing_values.rst b/docs/language/managing_values.rst
index 38667378d..2b4382fe0 100644
--- a/docs/language/managing_values.rst
+++ b/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.
.. 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.
+ It is not common practice for the program account to hold native Solana tokens.
.. code-block:: solidity
diff --git a/docs/targets/solana.rst b/docs/targets/solana.rst
index 68e0398fb..3995281d0 100644
--- a/docs/targets/solana.rst
+++ b/docs/targets/solana.rst
@@ -45,9 +45,11 @@ Runtime
- The Solana target requires `Solana `_ v1.8.1.
- 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 ` 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 ` the necessary accounts for the transaction.
+- The keyword ``this`` returns the contract's program account, also know as program id.
+
Compute budget
++++++++++++++
diff --git a/integration/anchor/tests/anchor.ts b/integration/anchor/tests/anchor.ts
index 4f7f2ebf7..b4b0f5d86 100644
--- a/integration/anchor/tests/anchor.ts
+++ b/integration/anchor/tests/anchor.ts
@@ -17,7 +17,7 @@ describe("Anchor", () => {
const program = anchor.workspace.Anchor as Program;
- 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;
diff --git a/integration/polkadot/call_flags.sol b/integration/polkadot/call_flags.sol
index 9da059a43..fc903fc5f 100644
--- a/integration/polkadot/call_flags.sol
+++ b/integration/polkadot/call_flags.sol
@@ -57,7 +57,7 @@ contract CallFlags {
}
// 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);
}
}
diff --git a/integration/polkadot/issue666.sol b/integration/polkadot/issue666.sol
index 3dcc0dfbc..ae62d5f21 100644
--- a/integration/polkadot/issue666.sol
+++ b/integration/polkadot/issue666.sol
@@ -11,7 +11,7 @@ contract Inc {
_flipper = _flipperContract;
}
- function superFlip () pure public {
+ function superFlip () view public {
_flipper.flip();
}
}
diff --git a/integration/solana/balances.spec.ts b/integration/solana/balances.spec.ts
index de3439237..d82efebc2 100644
--- a/integration/solana/balances.spec.ts
+++ b/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 res = await program.methods.getBalance(payer.publicKey)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: payer.publicKey, isSigner: false, isWritable: false }])
.view();
@@ -38,7 +37,6 @@ describe('Deploy solang contract and test', function () {
await sendAndConfirmTransaction(provider.connection, transaction, [payer]);
await program.methods.send(payer.publicKey, new BN(500))
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([
{ pubkey: storage.publicKey, isSigner: true, isWritable: true },
{ pubkey: payer.publicKey, isSigner: false, isWritable: true }
diff --git a/integration/solana/builtins.spec.ts b/integration/solana/builtins.spec.ts
index e46854603..20f41bd81 100644
--- a/integration/solana/builtins.spec.ts
+++ b/integration/solana/builtins.spec.ts
@@ -29,7 +29,6 @@ describe('Testing builtins', function () {
expect(res['return1']).toEqual([0xfe]);
res = await program.methods.mrNow()
- .accounts({ dataAccount: storage.publicKey })
.view();
let now = Math.floor(+new Date() / 1000);
@@ -40,7 +39,6 @@ describe('Testing builtins', function () {
expect(ts).toBeGreaterThan(now - 120);
res = await program.methods.mrSlot()
- .accounts({ dataAccount: storage.publicKey })
.view();
let sol_slot = Number(res);
diff --git a/integration/solana/calls.spec.ts b/integration/solana/calls.spec.ts
index 7a8cfb748..9bafcdcc7 100644
--- a/integration/solana/calls.spec.ts
+++ b/integration/solana/calls.spec.ts
@@ -26,22 +26,16 @@ describe('Testing calls', function () {
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()
- .accounts({ dataAccount: caller.storage.publicKey })
.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();
res = await callee.program.methods.getX()
@@ -50,33 +44,30 @@ describe('Testing calls', function () {
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();
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();
expect(res.return0).toEqual(new BN(24));
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();
expect(res.return0).toEqual(new BN(10));
diff --git a/integration/solana/create_contract.sol b/integration/solana/create_contract.sol
index 36423ec62..4b12718b6 100644
--- a/integration/solana/create_contract.sol
+++ b/integration/solana/create_contract.sol
@@ -4,25 +4,24 @@ contract creator {
Child public c;
Child public c_metas;
- function create_child(address child) external {
+ function create_child() external {
print("Going to create child");
- c = new Child{address: child}();
+ c = new Child();
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");
- Seed1 s = new Seed1{address: child}(seed, bump, space);
+ Seed1 s = new Seed1(seed, bump, space);
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");
- new Seed2{address: child}(seed, space);
-
+ new Seed2(seed, space);
}
function create_child_with_metas(address child, address payer) public {
@@ -37,8 +36,8 @@ contract creator {
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();
}
}
@@ -88,9 +87,9 @@ contract Seed2 {
}
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.");
}
}
diff --git a/integration/solana/create_contract.spec.ts b/integration/solana/create_contract.spec.ts
index aff92c313..4ebbd9488 100644
--- a/integration/solana/create_contract.spec.ts
+++ b/integration/solana/create_contract.spec.ts
@@ -22,15 +22,13 @@ describe('ChildContract', function () {
let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
let child = Keypair.generate();
- const signature = await program.methods.createChild(child.publicKey)
+ const signature = await program.methods.createChild()
.accounts({
dataAccount: storage.publicKey,
+ Child_programId: child_program,
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])
.rpc({ commitment: 'confirmed' });
@@ -51,15 +49,12 @@ describe('ChildContract', function () {
let [address, bump] = await PublicKey.findProgramAddress([seed], seed_program);
const signature = await program.methods.createSeed1(
- address, seed, Buffer.from([bump]), new BN(711))
+ seed, Buffer.from([bump]), new BN(711))
.accounts({
- dataAccount: storage.publicKey,
+ Seed1_programId: seed_program,
payer: payer.publicKey,
+ Seed1_dataAccount: address,
})
- .remainingAccounts([
- { pubkey: seed_program, isSigner: false, isWritable: false },
- { pubkey: address, isSigner: false, isWritable: true },
- ])
.signers([payer])
.rpc({ commitment: 'confirmed' });
@@ -84,15 +79,12 @@ describe('ChildContract', function () {
let seed = Buffer.concat([bare_seed, Buffer.from([bump])]);
const signature = await program.methods.createSeed2(
- address, seed, new BN(9889))
+ seed, new BN(9889))
.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])
.rpc({ commitment: 'confirmed' });
@@ -122,9 +114,11 @@ describe('ChildContract', function () {
let child_program = new PublicKey("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT");
const signature = await program.methods.createChildWithMetas(child.publicKey, payer.publicKey)
- .accounts({ dataAccount: storage.publicKey })
+ .accounts({
+ dataAccount: storage.publicKey,
+ Child_programId: child_program,
+ })
.remainingAccounts([
- { pubkey: child_program, isSigner: false, isWritable: false },
{ pubkey: child.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");
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' });
const tx = await provider.connection.getTransaction(signature, {
diff --git a/integration/solana/events.spec.ts b/integration/solana/events.spec.ts
index d16fd242b..e676c4a9e 100644
--- a/integration/solana/events.spec.ts
+++ b/integration/solana/events.spec.ts
@@ -10,7 +10,6 @@ describe('Test events', function () {
const { program, storage } = await loadContractAndCallConstructor('MyContractEvents');
const res = await program.methods.test()
- .accounts({ dataAccount: storage.publicKey })
.simulate();
const event1 = res.events[0];
diff --git a/integration/solana/runtime_errors.spec.ts b/integration/solana/runtime_errors.spec.ts
index 6166f2888..5ea4f7f6e 100644
--- a/integration/solana/runtime_errors.spec.ts
+++ b/integration/solana/runtime_errors.spec.ts
@@ -48,7 +48,7 @@ describe('Runtime Errors', function () {
}
try {
- let res = await program.methods.invalidInstruction().accounts({ dataAccount: storage.publicKey }).simulate();
+ let res = await program.methods.invalidInstruction().simulate();
} catch (e: any) {
const logs = e.simulationResponse.logs;
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 {
- 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) {
const logs = e.simulationResponse.logs;
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 {
- let res = await program.methods.iWillRevert().accounts({ dataAccount: storage.publicKey }).simulate();
+ let res = await program.methods.iWillRevert().simulate();
} catch (e: any) {
const logs = e.simulationResponse.logs;
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 {
- 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) {
const logs = e.simulationResponse.logs;
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 {
- 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) {
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,
@@ -90,7 +90,7 @@ describe('Runtime Errors', function () {
}
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) {
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,
@@ -99,7 +99,7 @@ describe('Runtime Errors', function () {
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) {
const logs = e.simulationResponse.logs;
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 {
- 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) {
const logs = e.simulationResponse.logs;
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 {
- 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) {
const logs = e.simulationResponse.logs;
expect(logs).toContain(`Program log: runtime_error: truncated type overflows in runtime_errors.sol:90:37-42,
diff --git a/integration/solana/simple.spec.ts b/integration/solana/simple.spec.ts
index 0c7ebe541..906736b28 100644
--- a/integration/solana/simple.spec.ts
+++ b/integration/solana/simple.spec.ts
@@ -29,121 +29,121 @@ describe('Simple solang tests', function () {
// TEST Basic enums
// 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
- let res = await program.methods.isMul({ mul: {} }).accounts({ dataAccount: storage.publicKey }).view();
+ let res = await program.methods.isMul({ mul: {} }).view();
expect(res).toBe(true);
- res = await program.methods.returnDiv().accounts({ dataAccount: storage.publicKey }).view();
+ res = await program.methods.returnDiv().view();
expect(res.div).toBeDefined();
// TEST uint and int types, and arithmetic/bitwise ops
res = await program.methods.opI64({ add: {} }, new BN(1000), new BN(4100)).view();
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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
// 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);
- 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));
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
// 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]);
// TEST bytes5
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]);
- 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]);
res = await program.methods.opU85({ or: {} },
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]);
res = await program.methods.opU85({ and: {} },
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]);
res = await program.methods.opU85({ xor: {} },
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]);
// TEST bytes14
res = await program.methods.opU814Shift({ shl: {} },
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]);
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]);
res = await program.methods.opU814({ or: {} },
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]);
res = await program.methods.opU814({ and: {} },
Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
- Buffer.from("000000000000000000ff00000000", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+ Buffer.from("000000000000000000ff00000000", "hex")).view();
expect(res).toStrictEqual(
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00]);
res = await program.methods.opU814({ xor: {} },
Buffer.from("deadcafe123456789abcdefbeef7", "hex"),
- Buffer.from("ff00000000000000000000000000", "hex")).accounts({ dataAccount: storage.publicKey }).view();
+ Buffer.from("ff00000000000000000000000000", "hex")).view();
expect(res).toStrictEqual(
[0x21, 0xad, 0xca, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xfb, 0xee, 0xf7]);
diff --git a/integration/solana/simple_collectible.spec.ts b/integration/solana/simple_collectible.spec.ts
index 6e4115942..a9959401c 100644
--- a/integration/solana/simple_collectible.spec.ts
+++ b/integration/solana/simple_collectible.spec.ts
@@ -72,7 +72,6 @@ describe('Simple collectible', function () {
await program.methods.transferOwnership(
owner_token_account.address,
new_owner_token_account.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([
{ pubkey: new_owner_token_account.address, isSigner: false, isWritable: true },
{ pubkey: owner_token_account.address, isSigner: false, isWritable: true },
diff --git a/integration/solana/system_instruction.spec.ts b/integration/solana/system_instruction.spec.ts
index 41a99cf87..930272f9a 100644
--- a/integration/solana/system_instruction.spec.ts
+++ b/integration/solana/system_instruction.spec.ts
@@ -28,7 +28,6 @@ describe('Test system instructions', function () {
{ pubkey: payer.publicKey, isSigner: true, isWritable: false },
{ pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, to_key_pair]).rpc();
});
@@ -51,7 +50,6 @@ describe('Test system instructions', function () {
{ pubkey: to_key_pair, isSigner: false, isWritable: true },
{ pubkey: base_keypair.publicKey, isSigner: true, isWritable: false },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, base_keypair]).rpc();
});
@@ -67,7 +65,6 @@ describe('Test system instructions', function () {
{ pubkey: payer.publicKey, isSigner: false, isWritable: false },
{ pubkey: to_key_pair.publicKey, isSigner: true, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, to_key_pair]).rpc();
});
@@ -86,7 +83,6 @@ describe('Test system instructions', function () {
{ pubkey: payer.publicKey, isSigner: false, isWritable: false },
{ pubkey: to_key_pair, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer]).rpc();
});
@@ -102,7 +98,6 @@ describe('Test system instructions', function () {
{ pubkey: payer.publicKey, isSigner: false, isWritable: true },
{ pubkey: dest.publicKey, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer]).rpc();
});
@@ -128,7 +123,6 @@ describe('Test system instructions', function () {
{ pubkey: dest.publicKey, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: false },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer]).rpc();
});
@@ -142,7 +136,6 @@ describe('Test system instructions', function () {
.remainingAccounts([
{ pubkey: account.publicKey, isSigner: true, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, account]).rpc();
});
@@ -163,7 +156,6 @@ describe('Test system instructions', function () {
{ pubkey: account.publicKey, isSigner: true, isWritable: false },
{ pubkey: derived_key, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, account]).rpc();
});
@@ -187,7 +179,6 @@ describe('Test system instructions', function () {
{ pubkey: derived_account, isSigner: false, isWritable: true },
{ pubkey: base_address.publicKey, isSigner: true, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, base_address]).rpc();
});
@@ -207,7 +198,6 @@ describe('Test system instructions', function () {
{ pubkey: payer.publicKey, isSigner: false, isWritable: true },
{ pubkey: nonce.publicKey, isSigner: true, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([payer, nonce]).rpc();
await program.methods.advanceNonceAccount(
@@ -218,7 +208,6 @@ describe('Test system instructions', function () {
{ pubkey: authority.publicKey, isSigner: true, isWritable: false },
{ pubkey: nonce.publicKey, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([authority]).rpc();
await program.methods.withdrawNonceAccount(
@@ -233,7 +222,6 @@ describe('Test system instructions', function () {
{ pubkey: nonce.publicKey, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([authority]).rpc();
const new_authority = Keypair.generate();
@@ -246,7 +234,6 @@ describe('Test system instructions', function () {
{ pubkey: authority.publicKey, isSigner: true, isWritable: false },
{ pubkey: nonce.publicKey, isSigner: false, isWritable: true },
])
- .accounts({ dataAccount: storage.publicKey })
.signers([authority]).rpc();
});
});
diff --git a/integration/solana/token.spec.ts b/integration/solana/token.spec.ts
index b090e1456..d50b5f883 100644
--- a/integration/solana/token.spec.ts
+++ b/integration/solana/token.spec.ts
@@ -32,7 +32,6 @@ describe('Create spl-token and use from solidity', function () {
.accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: mint, isSigner: false, isWritable: false }])
.view();
-
expect(total_supply.toNumber()).toBe(0);
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)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
.view();
@@ -71,7 +69,6 @@ describe('Create spl-token and use from solidity', function () {
expect(total_supply.toNumber()).toBe(100000);
balance = await program.methods.getBalance(tokenAccount.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
.view();
@@ -92,7 +89,6 @@ describe('Create spl-token and use from solidity', function () {
otherTokenAccount.address,
payer.publicKey,
new BN(70000))
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([
{ pubkey: otherTokenAccount.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);
balance = await program.methods.getBalance(tokenAccount.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
.view();
expect(balance.toNumber()).toBe(30000);
balance = await program.methods.getBalance(otherTokenAccount.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
.view();
@@ -135,7 +129,6 @@ describe('Create spl-token and use from solidity', function () {
.signers([theOutsider])
.rpc();
-
total_supply = await program.methods.totalSupply()
.accounts({ dataAccount: storage.publicKey })
.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);
balance = await program.methods.getBalance(tokenAccount.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: tokenAccount.address, isSigner: false, isWritable: false }])
.view();
expect(balance.toNumber()).toBe(30000);
balance = await program.methods.getBalance(otherTokenAccount.address)
- .accounts({ dataAccount: storage.publicKey })
.remainingAccounts([{ pubkey: otherTokenAccount.address, isSigner: false, isWritable: false }])
.view();
diff --git a/integration/solana/verify_sig.spec.ts b/integration/solana/verify_sig.spec.ts
index 474224037..120d239ed 100644
--- a/integration/solana/verify_sig.spec.ts
+++ b/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))
.preInstructions([instr1])
.accounts({
- dataAccount: storage.publicKey,
SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
})
.view();
@@ -57,7 +56,6 @@ describe('Signature Check', function () {
const result = await program.methods.verify(payer.publicKey, message, Buffer.from(broken_signature))
.preInstructions([instr1])
.accounts({
- dataAccount: storage.publicKey,
SysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY
})
.view();
diff --git a/src/abi/tests.rs b/src/abi/tests.rs
index a42acea4d..a657746a8 100644
--- a/src/abi/tests.rs
+++ b/src/abi/tests.rs
@@ -190,15 +190,7 @@ fn instructions_and_types() {
assert!(idl.instructions[0].docs.is_none());
assert_eq!(
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].returns.is_none());
@@ -208,15 +200,7 @@ fn instructions_and_types() {
assert!(idl.instructions[1].docs.is_none());
assert_eq!(
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_eq!(idl.instructions[1].returns, Some(IdlType::U64));
@@ -226,15 +210,7 @@ fn instructions_and_types() {
assert!(idl.instructions[2].docs.is_none());
assert_eq!(
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!(
idl.instructions[2].args,
@@ -274,15 +250,7 @@ fn instructions_and_types() {
);
assert_eq!(
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!(
idl.instructions[4].args,
@@ -301,15 +269,7 @@ fn instructions_and_types() {
);
assert_eq!(
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_eq!(idl.instructions[5].returns, Some(IdlType::String));
@@ -318,15 +278,7 @@ fn instructions_and_types() {
assert!(idl.instructions[6].docs.is_none());
assert_eq!(
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_eq!(
@@ -397,33 +349,14 @@ contract caller {
assert!(idl.instructions[0].docs.is_none());
assert_eq!(
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].returns.is_none());
assert_eq!(idl.instructions[1].name, "emitAll");
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!(
idl.instructions[1].args,
vec![
@@ -552,32 +485,13 @@ fn types() {
assert!(idl.instructions[0].docs.is_none());
assert_eq!(
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].returns.is_none());
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!(
idl.instructions[1].args,
vec![
@@ -655,15 +569,7 @@ fn constructor() {
assert!(idl.instructions[0].docs.is_none());
assert_eq!(
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[0].args,
@@ -679,15 +585,7 @@ fn constructor() {
assert!(idl.instructions[1].docs.is_none());
assert_eq!(
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_eq!(idl.instructions[1].returns, Some(IdlType::U64));
@@ -720,15 +618,7 @@ contract Testing {
assert!(idl.instructions[0].args.is_empty());
assert_eq!(
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");
@@ -1519,7 +1409,7 @@ fn data_account_signer() {
contract caller {
// signer required
@payer(wallet)
- constructor(address wallet) {}
+ constructor() {}
}"#;
let mut ns = generate_namespace(src);
@@ -1534,36 +1424,12 @@ fn data_account_signer() {
assert_eq!(
idl.instructions[0].accounts,
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());
let src = r#"
@@ -1585,33 +1451,9 @@ fn data_account_signer() {
assert_eq!(
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![],
- }),
- 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);
@@ -1642,40 +1484,13 @@ fn accounts_call_chain() {
assert_eq!(idl.instructions[0].name, "new");
assert_eq!(
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].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");
@@ -1723,48 +1538,16 @@ fn accounts_on_recursion() {
assert_eq!(idl.instructions[0].name, "new");
assert_eq!(
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].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: "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!(
idl.instructions[0].accounts,
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].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!(
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: "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].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].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: "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!(
idl.instructions[2].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: "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!(
idl.instructions[3].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: "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!(
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![],
- }),
- 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 {
Child public c;
- function create_child(address child, address payer) external returns (uint64) {
+ function create_child() external returns (uint64) {
print("Going to create child");
- c = new Child{address: child}(payer);
+ c = new Child();
return c.say_hello();
}
@@ -2196,7 +1812,7 @@ contract creator {
contract Child {
@payer(payer)
@space(511 + 7)
- constructor(address payer) {
+ constructor() {
print("In child constructor");
}
@@ -2218,42 +1834,12 @@ contract Child {
assert_eq!(
idl.instructions[2].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: "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;
@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!(
idl.instructions[0].accounts,
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);
}
+
+#[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![],
+ })
+}
diff --git a/src/bin/languageserver/mod.rs b/src/bin/languageserver/mod.rs
index a4786b166..587f6a1ff 100644
--- a/src/bin/languageserver/mod.rs
+++ b/src/bin/languageserver/mod.rs
@@ -1095,9 +1095,6 @@ impl<'a> Builder<'a> {
if let Some(optsalt) = &call_args.salt {
self.expression(optsalt, symtab);
}
- if let Some(address) = &call_args.address {
- self.expression(address, symtab);
- }
if let Some(seeds) = &call_args.seeds {
self.expression(seeds, symtab);
}
diff --git a/src/codegen/cfg.rs b/src/codegen/cfg.rs
index bcecb16dc..fac877008 100644
--- a/src/codegen/cfg.rs
+++ b/src/codegen/cfg.rs
@@ -132,6 +132,7 @@ pub enum Instr {
/// Call external functions. If the call fails, set the success failure
/// or abort if this is None
ExternalCall {
+ loc: Loc,
success: Option,
address: Option,
accounts: Option,
@@ -417,6 +418,8 @@ pub struct ControlFlowGraph {
current: usize,
// A mapping between the res of an array and the res of the temp var holding its length.
pub array_lengths_temps: ArrayLengthVars,
+ /// Is this a modifier dispatch for which function number?
+ pub modifier: Option,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -488,6 +491,7 @@ impl ControlFlowGraph {
selector: Vec::new(),
current: 0,
array_lengths_temps: IndexMap::new(),
+ modifier: None,
};
cfg.new_basic_block("entry".to_string());
@@ -510,6 +514,7 @@ impl ControlFlowGraph {
selector: Vec::new(),
current: 0,
array_lengths_temps: IndexMap::new(),
+ modifier: None,
}
}
@@ -1181,7 +1186,7 @@ impl ControlFlowGraph {
gas,
callty,
contract_function_no,
- flags
+ flags, ..
} => {
format!(
"{} = external call::{} address:{} payload:{} value:{} gas:{} accounts:{} seeds:{} contract|function:{} flags:{}",
@@ -1511,6 +1516,7 @@ pub fn generate_cfg(
cfg.public = public;
cfg.nonpayable = nonpayable;
cfg.selector = ns.functions[func_no].selector(ns, &contract_no);
+ cfg.modifier = Some(func_no);
}
}
diff --git a/src/codegen/constant_folding.rs b/src/codegen/constant_folding.rs
index 164fcf153..32b54bc91 100644
--- a/src/codegen/constant_folding.rs
+++ b/src/codegen/constant_folding.rs
@@ -267,6 +267,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
}
}
Instr::ExternalCall {
+ loc,
success,
address,
payload,
@@ -296,6 +297,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
if !dry_run {
cfg.blocks[block_no].instr[instr_no] = Instr::ExternalCall {
+ loc: *loc,
success: *success,
address,
accounts,
diff --git a/src/codegen/constructor.rs b/src/codegen/constructor.rs
index 0926aee4d..2616c8ddc 100644
--- a/src/codegen/constructor.rs
+++ b/src/codegen/constructor.rs
@@ -8,6 +8,8 @@ use crate::sema::{
ast,
ast::{CallArgs, Function, Namespace, Type},
};
+use crate::Target;
+use num_bigint::{BigInt, Sign};
use solang_parser::pt::Loc;
use super::encoding::abi_encode;
@@ -44,10 +46,18 @@ pub(super) fn call_constructor(
.salt
.as_ref()
.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
.seeds
.as_ref()
diff --git a/src/codegen/dispatch/solana.rs b/src/codegen/dispatch/solana.rs
index f21922917..82353b5b3 100644
--- a/src/codegen/dispatch/solana.rs
+++ b/src/codegen/dispatch/solana.rs
@@ -12,6 +12,7 @@ use num_traits::Zero;
use solang_parser::{pt, pt::Loc};
use crate::codegen::encoding::{abi_decode, abi_encode};
+use crate::sema::solana_accounts::BuiltinAccounts;
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}"));
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 {
- 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);
}
diff --git a/src/codegen/expression.rs b/src/codegen/expression.rs
index 82b243355..6fb36d0b7 100644
--- a/src/codegen/expression.rs
+++ b/src/codegen/expression.rs
@@ -28,7 +28,7 @@ use crate::sema::{
expression::ResolveTo,
};
use crate::Target;
-use num_bigint::BigInt;
+use num_bigint::{BigInt, Sign};
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
use solang_parser::pt;
use solang_parser::pt::{CodeLocation, Loc};
@@ -1589,6 +1589,7 @@ fn payable_send(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success: Some(success),
address: Some(address),
accounts: None,
@@ -1658,6 +1659,7 @@ fn payable_transfer(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success: None,
accounts: None,
seeds: None,
@@ -2162,6 +2164,14 @@ fn expr_builtin(
}
}
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
let codegen_expr = Expression::Builtin {
loc: *loc,
@@ -2794,6 +2804,7 @@ pub fn emit_function_call(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success: Some(success),
address: Some(address),
payload: args,
@@ -2908,6 +2919,7 @@ pub fn emit_function_call(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success,
accounts,
address: Some(address),
@@ -2994,6 +3006,7 @@ pub fn emit_function_call(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success,
accounts: None,
seeds: None,
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 4e934a6b6..cf22f3ed1 100644
--- a/src/codegen/mod.rs
+++ b/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) {
@@ -1755,7 +1756,6 @@ pub enum Builtin {
Ripemd160,
Sender,
Slot,
- ProgramId,
Sha256,
Signature,
SignatureVerify,
@@ -1813,7 +1813,6 @@ impl From<&ast::Builtin> for Builtin {
ast::Builtin::Ripemd160 => Builtin::Ripemd160,
ast::Builtin::Sender => Builtin::Sender,
ast::Builtin::Slot => Builtin::Slot,
- ast::Builtin::ProgramId => Builtin::ProgramId,
ast::Builtin::Sha256 => Builtin::Sha256,
ast::Builtin::Signature => Builtin::Signature,
ast::Builtin::SignatureVerify => Builtin::SignatureVerify,
diff --git a/src/codegen/solana_accounts/account_collection.rs b/src/codegen/solana_accounts/account_collection.rs
index 90bc90274..dc94a2dd8 100644
--- a/src/codegen/solana_accounts/account_collection.rs
+++ b/src/codegen/solana_accounts/account_collection.rs
@@ -3,12 +3,13 @@
use crate::codegen::cfg::{ASTFunction, ControlFlowGraph, Instr, InternalCallTy};
use crate::codegen::solana_accounts::account_from_number;
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::solana_accounts::BuiltinAccounts;
use crate::sema::Recurse;
use indexmap::IndexSet;
use solang_parser::diagnostics::Diagnostic;
+use solang_parser::pt;
use solang_parser::pt::{FunctionTy, Loc};
use std::collections::{HashSet, VecDeque};
@@ -33,7 +34,7 @@ struct RecurseData<'a> {
impl RecurseData<'_> {
/// 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]
.solana_accounts
.borrow()
@@ -63,7 +64,7 @@ impl RecurseData<'_> {
fn add_system_account(&mut self) {
self.add_account(
BuiltinAccounts::SystemAccount.to_string(),
- SolanaAccount {
+ &SolanaAccount {
loc: Loc::Codegen,
is_writer: 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];
- 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() {
func.solana_accounts.borrow_mut().insert(
BuiltinAccounts::SystemAccount.to_string(),
@@ -234,7 +211,7 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
let accounts_to_add =
data.functions[*ast_no].solana_accounts.borrow().clone();
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);
}
Instr::Constructor {
+ loc,
encoded_args,
value,
gas,
@@ -332,6 +310,7 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
seeds,
accounts,
constructor_no,
+ contract_no,
..
} => {
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
// need to collect accounts for the IDL.
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();
}
Instr::ExternalCall {
+ loc,
address,
accounts,
seeds,
@@ -400,6 +350,14 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
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 {
address.recurse(data, check_expression);
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) {
data.add_account(
account,
- SolanaAccount {
+ &SolanaAccount {
loc: Loc::Codegen,
is_signer: false,
is_writer: false,
generated: true,
},
);
+ program_id_populated = true;
}
}
}
- if let Some(accounts) = accounts {
- accounts.recurse(data, check_expression);
- }
if let Some(seeds) = seeds {
seeds.recurse(data, check_expression);
}
@@ -428,17 +384,11 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
gas.recurse(data, check_expression);
// External calls always need the 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 {
@@ -471,7 +421,7 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
} => {
data.add_account(
BuiltinAccounts::ClockAccount.to_string(),
- SolanaAccount {
+ &SolanaAccount {
loc: Loc::Codegen,
is_signer: false,
is_writer: false,
@@ -485,7 +435,7 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
} => {
data.add_account(
BuiltinAccounts::InstructionAccount.to_string(),
- SolanaAccount {
+ &SolanaAccount {
loc: Loc::Codegen,
is_writer: false,
is_signer: false,
@@ -505,3 +455,82 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
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));
+}
diff --git a/src/codegen/solana_accounts/account_management.rs b/src/codegen/solana_accounts/account_management.rs
index 36c05009b..a35f6c7e1 100644
--- a/src/codegen/solana_accounts/account_management.rs
+++ b/src/codegen/solana_accounts/account_management.rs
@@ -1,12 +1,11 @@
// 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::{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 num_bigint::BigInt;
-use num_traits::Zero;
use solang_parser::pt::Loc;
use std::collections::{HashSet, VecDeque};
@@ -26,8 +25,10 @@ pub(crate) fn manage_contract_accounts(contract_no: usize, ns: &mut Namespace) {
.copied()
.unwrap();
traverse_cfg(
- &mut ns.contracts[contract_no].cfg[cfg_no],
+ &mut ns.contracts,
+ contract_no,
&ns.functions,
+ cfg_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 {
let dispatch = ns.contracts[contract_no]
.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");
- 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.
-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;
}
@@ -54,11 +67,22 @@ fn traverse_cfg(cfg: &mut ControlFlowGraph, functions: &[Function], ast_no: usiz
visited.insert(0);
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) {
queue.push_back(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.
/// 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 = 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 = 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]
.solana_accounts
.borrow()
- .get_index_of(name)
+ .get_index_of(&name_to_index)
.unwrap();
let ptr_to_address = accounts_vector_key_at_index(account_index);
account_metas.push(account_meta_literal(
@@ -119,38 +140,40 @@ fn process_instruction(instr: &mut Instr, functions: &[Function], ast_no: usize)
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,
- };
+ _ => (),
}
}
diff --git a/src/codegen/solana_deploy.rs b/src/codegen/solana_deploy.rs
index 072cfcb43..5db682a5f 100644
--- a/src/codegen/solana_deploy.rs
+++ b/src/codegen/solana_deploy.rs
@@ -11,6 +11,7 @@ use crate::sema::ast::{
self, ArrayLength, CallTy, ConstructorAnnotation, Function, FunctionAttributes, Namespace,
StructType,
};
+use crate::sema::solana_accounts::BuiltinAccounts;
use base58::ToBase58;
use num_bigint::{BigInt, Sign};
use num_traits::{ToPrimitive, Zero};
@@ -49,12 +50,17 @@ pub(super) fn solana_deploy(
ty: Type::Address(false),
value: BigInt::from_bytes_be(Sign::Plus, program_id),
}),
- right: Box::new(Expression::Builtin {
+ right: Expression::Load {
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());
@@ -265,14 +271,30 @@ pub(super) fn solana_deploy(
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 {
loc: Loc::Codegen,
- ty: account_info_ty,
+ ty: account_info_ty.clone(),
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_data_acc = retrieve_key_from_account_info(data_acc_var);
cfg.add(
vartab,
@@ -285,16 +307,7 @@ pub(super) fn solana_deploy(
dimensions: vec![2],
values: vec![
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),
}
} else {
- Expression::Builtin {
+ let addr_ptr = Expression::Builtin {
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![],
+ };
+ Expression::Load {
+ loc: Loc::Codegen,
+ ty: Type::Address(false),
+ expr: Box::new(addr_ptr),
}
},
offset: Expression::NumberLiteral {
@@ -537,6 +555,7 @@ pub(super) fn solana_deploy(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: Loc::Codegen,
success: None,
seeds,
address: Some(Expression::NumberLiteral {
diff --git a/src/codegen/statements/try_catch.rs b/src/codegen/statements/try_catch.rs
index aab518a67..909d46bbe 100644
--- a/src/codegen/statements/try_catch.rs
+++ b/src/codegen/statements/try_catch.rs
@@ -257,6 +257,7 @@ fn exec_try(
cfg.add(
vartab,
Instr::ExternalCall {
+ loc: *loc,
success: Some(success),
address: Some(address),
accounts: None,
diff --git a/src/codegen/subexpression_elimination/instruction.rs b/src/codegen/subexpression_elimination/instruction.rs
index 6488c8c36..b3e36def5 100644
--- a/src/codegen/subexpression_elimination/instruction.rs
+++ b/src/codegen/subexpression_elimination/instruction.rs
@@ -376,6 +376,7 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
}
Instr::ExternalCall {
+ loc,
success,
address,
accounts,
@@ -404,6 +405,7 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
.map(|expr| self.regenerate_expression(expr, ave, cst).1);
Instr::ExternalCall {
+ loc: *loc,
success: *success,
address: new_address,
accounts: new_accounts,
diff --git a/src/emit/solana/mod.rs b/src/emit/solana/mod.rs
index 2de319146..9cfbf728c 100644
--- a/src/emit/solana/mod.rs
+++ b/src/emit/solana/mod.rs
@@ -1054,7 +1054,6 @@ impl SolanaTarget {
fn build_external_call<'b>(
&self,
binary: &Binary,
- address: PointerValue<'b>,
payload: PointerValue<'b>,
payload_len: IntValue<'b>,
contract_args: ContractArgs<'b>,
@@ -1077,16 +1076,16 @@ impl SolanaTarget {
seeds,
binary.builder.build_int_cast(
len,
- external_call.get_type().get_param_types()[5].into_int_type(),
+ external_call.get_type().get_param_types()[4].into_int_type(),
"len",
),
)
})
.unwrap_or((
- external_call.get_type().get_param_types()[4]
+ external_call.get_type().get_param_types()[3]
.ptr_type(AddressSpace::default())
.const_null(),
- external_call.get_type().get_param_types()[5]
+ external_call.get_type().get_param_types()[4]
.into_int_type()
.const_zero(),
));
@@ -1096,7 +1095,6 @@ impl SolanaTarget {
&[
payload.into(),
payload_len.into(),
- address.into(),
program_id.into(),
seeds.into(),
seeds_len.into(),
diff --git a/src/emit/solana/target.rs b/src/emit/solana/target.rs
index 0fdb97746..f0e08a9c3 100644
--- a/src/emit/solana/target.rs
+++ b/src/emit/solana/target.rs
@@ -10,8 +10,7 @@ use crate::emit::{ContractArgs, TargetRuntime, Variable};
use crate::sema::ast::{self, Namespace};
use inkwell::types::{BasicType, BasicTypeEnum, IntType};
use inkwell::values::{
- ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
- PointerValue,
+ ArrayValue, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue,
};
use inkwell::{AddressSpace, IntPredicate};
use num_traits::ToPrimitive;
@@ -1350,11 +1349,11 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
) {
let address = address.unwrap();
+ contract_args.program_id = Some(address);
if contract_args.accounts.is_some() {
- contract_args.program_id = Some(address);
self.build_invoke_signed_c(binary, function, payload, payload_len, contract_args);
} 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 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 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 {
kind: codegen::Builtin::Calldata,
diff --git a/src/sema/ast.rs b/src/sema/ast.rs
index cda906af8..e875be7ad 100644
--- a/src/sema/ast.rs
+++ b/src/sema/ast.rs
@@ -342,7 +342,7 @@ pub struct Function {
/// This struct represents a Solana account. There is no name field, because
/// it is stored in a IndexMap (see above)
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SolanaAccount {
pub loc: pt::Loc,
pub is_signer: bool,
@@ -1208,7 +1208,6 @@ pub struct CallArgs {
pub gas: Option>,
pub salt: Option>,
pub value: Option>,
- pub address: Option>,
pub accounts: Option>,
pub seeds: Option>,
pub flags: Option>,
@@ -1263,6 +1262,8 @@ impl Recurse for Expression {
| Expression::Not { expr, .. }
| Expression::BitwiseNot { expr, .. }
| Expression::Negate { expr, .. }
+ | Expression::GetRef { expr, .. }
+ | Expression::NamedMember { array: expr, .. }
| Expression::StructMember { expr, .. } => expr.recurse(cx, f),
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,
BlockNumber,
Slot,
- ProgramId,
Timestamp,
Calldata,
Sender,
diff --git a/src/sema/builtin.rs b/src/sema/builtin.rs
index 4d123fa4d..2b8e38018 100644
--- a/src/sema/builtin.rs
+++ b/src/sema/builtin.rs
@@ -309,7 +309,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
});
// A list of all Solidity builtins variables
-static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
+static BUILTIN_VARIABLE: Lazy<[Prototype; 17]> = Lazy::new(|| {
[
Prototype {
builtin: Builtin::BlockCoinbase,
@@ -366,17 +366,6 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
doc: "Current slot number",
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 {
builtin: Builtin::Timestamp,
namespace: Some("block"),
diff --git a/src/sema/contracts.rs b/src/sema/contracts.rs
index f88ff0d97..abaf4a6b6 100644
--- a/src/sema/contracts.rs
+++ b/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 contract in contracts {
let context = ExprContext {
- function_no: None,
- contract_no: Some(contract.contract_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 {
@@ -231,6 +227,7 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
}
}
}
+ context.drop();
}
ns.diagnostics.extend(diagnostics);
diff --git a/src/sema/dotgraphviz.rs b/src/sema/dotgraphviz.rs
index 90ec6082b..a92310715 100644
--- a/src/sema/dotgraphviz.rs
+++ b/src/sema/dotgraphviz.rs
@@ -1477,9 +1477,6 @@ impl Dot {
if let Some(salt) = &call_args.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 {
self.add_expression(accounts, func, ns, node, String::from("accounts"));
}
diff --git a/src/sema/expression/constructor.rs b/src/sema/expression/constructor.rs
index c8a01554c..09ed0ee8a 100644
--- a/src/sema/expression/constructor.rs
+++ b/src/sema/expression/constructor.rs
@@ -10,7 +10,7 @@ use crate::sema::unused_variable::used_variable;
use crate::Target;
use solang_parser::diagnostics::Diagnostic;
use solang_parser::pt;
-use solang_parser::pt::CodeLocation;
+use solang_parser::pt::{CodeLocation, Visibility};
use std::collections::BTreeMap;
/// Resolve an new contract expression with positional arguments
@@ -60,15 +60,7 @@ fn constructor(
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
if circular_reference(no, context_contract_no, ns) {
@@ -268,6 +260,8 @@ pub fn constructor_named_args(
return Err(());
}
+ solana_constructor_check(loc, no, diagnostics, context, &call_args, ns);
+
// check for circular references
if circular_reference(no, context_contract_no, ns) {
diagnostics.push(Diagnostic::error(
@@ -580,3 +574,47 @@ pub(super) fn deprecated_constructor_arguments(
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(),
+ ));
+ }
+ }
+}
diff --git a/src/sema/expression/function_call.rs b/src/sema/expression/function_call.rs
index 15bf2af36..784012f72 100644
--- a/src/sema/expression/function_call.rs
+++ b/src/sema/expression/function_call.rs
@@ -2033,45 +2033,6 @@ pub(super) fn parse_call_args(
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" => {
if ns.target == Target::Solana {
diagnostics.push(Diagnostic::error(
@@ -2219,40 +2180,23 @@ pub(super) fn parse_call_args(
}
// 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)
diff --git a/src/sema/expression/member_access.rs b/src/sema/expression/member_access.rs
index 06632fc17..c5105a2d9 100644
--- a/src/sema/expression/member_access.rs
+++ b/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::resolve_expression::expression;
use crate::sema::expression::{ExprContext, ResolveTo};
+use crate::sema::solana_accounts::BuiltinAccounts;
use crate::sema::symtable::Symtable;
use crate::sema::unused_variable::{assigned_variable, used_variable};
+use crate::Target;
use num_bigint::{BigInt, Sign};
use num_traits::{FromPrimitive, One, Zero};
use solang_parser::diagnostics::Diagnostic;
@@ -246,11 +248,13 @@ pub(super) fn member_access(
};
} else if matches!(*elem_ty, Type::Struct(StructType::AccountInfo))
&& context.function_no.is_some()
+ && ns.target == Target::Solana
{
return if ns.functions[context.function_no.unwrap()]
.solana_accounts
.borrow()
.contains_key(&id.name)
+ || id.name == BuiltinAccounts::DataAccount
{
Ok(Expression::NamedMember {
loc: *loc,
diff --git a/src/sema/expression/mod.rs b/src/sema/expression/mod.rs
index d63a167bf..a2e8cc981 100644
--- a/src/sema/expression/mod.rs
+++ b/src/sema/expression/mod.rs
@@ -66,6 +66,26 @@ pub struct ExprContext {
pub lvalue: bool,
/// Are we resolving a yul function (it cannot have external dependencies)
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 {
diff --git a/src/sema/function_annotation.rs b/src/sema/function_annotation.rs
index 47af14750..2a669fb9b 100644
--- a/src/sema/function_annotation.rs
+++ b/src/sema/function_annotation.rs
@@ -255,6 +255,12 @@ pub(super) fn function_body_annotations(
format!("'{}' is a reserved account name", id.name),
));
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]
diff --git a/src/sema/mutability.rs b/src/sema/mutability.rs
index beecdf296..78f4ec065 100644
--- a/src/sema/mutability.rs
+++ b/src/sema/mutability.rs
@@ -8,6 +8,11 @@ use super::{
yul::ast::{YulExpression, YulStatement},
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};
#[derive(PartialEq, PartialOrd)]
@@ -18,6 +23,15 @@ enum Access {
Value,
}
+bitflags! {
+ #[derive(PartialEq, Eq, Copy, Clone, Debug)]
+ struct DataAccountUsage: u8 {
+ const NONE = 0;
+ const READ = 1;
+ const WRITE = 2;
+ }
+}
+
impl Access {
fn increase_to(&mut self, other: Access) {
if *self < other {
@@ -49,6 +63,7 @@ struct StateCheck<'a> {
func: &'a Function,
modifier: Option,
ns: &'a Namespace,
+ data_account: DataAccountUsage,
}
impl<'a> StateCheck<'a> {
@@ -148,6 +163,7 @@ fn check_mutability(func: &Function, ns: &Namespace) -> Vec {
func,
modifier: None,
ns,
+ data_account: DataAccountUsage::NONE,
};
for arg in &func.modifiers {
@@ -219,6 +235,38 @@ fn check_mutability(func: &Function, ns: &Namespace) -> Vec {
}
}
+ 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
}
@@ -260,7 +308,10 @@ fn recurse_statements(stmts: &[Statement], ns: &Namespace, state: &mut StateChec
Statement::Expression(_, _, expr) => {
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) => {
// This is either a list or internal/external function call
expr.recurse(state, read_expression);
@@ -309,17 +360,31 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
| Expression::PostIncrement { expr, .. }
| Expression::PostDecrement { expr, .. } => {
expr.recurse(state, write_expression);
+ return false;
}
Expression::Assign { left, right, .. } => {
right.recurse(state, read_expression);
left.recurse(state, write_expression);
+ return false;
}
- Expression::StorageVariable { loc, .. } => state.read(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() => {
- 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 {
kind: Builtin::FunctionSelector,
@@ -340,7 +405,6 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
| Builtin::BlockNumber
| Builtin::Slot
| Builtin::Timestamp
- | Builtin::ProgramId
| Builtin::BlockCoinbase
| Builtin::BlockDifficulty
| Builtin::BlockHash
@@ -354,6 +418,7 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
| Builtin::Accounts,
..
} => state.read(loc),
+
Expression::Builtin {
loc,
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,
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, .. } => {
state.write(loc);
@@ -398,11 +466,12 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
CallTy::Static => state.read(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 {
@@ -412,20 +481,33 @@ fn write_expression(expr: &Expression, state: &mut StateCheck) -> bool {
}
| Expression::Subscript { loc, array, .. } => {
if array.ty().is_contract_storage() {
+ state.data_account |= DataAccountUsage::WRITE;
state.write(loc);
return false;
}
}
Expression::Variable { loc, ty, var_no: _ } => {
if ty.is_contract_storage() && !expr.ty().is_contract_storage() {
+ state.data_account |= DataAccountUsage::WRITE;
state.write(loc);
return false;
}
}
Expression::StorageVariable { loc, .. } => {
+ state.data_account |= DataAccountUsage::WRITE;
state.write(loc);
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() {
state.write(loc);
}
+
+ match builtin_ty {
+ YulBuiltInFunction::SStore => {
+ state.data_account |= DataAccountUsage::WRITE;
+ }
+ YulBuiltInFunction::SLoad => {
+ state.data_account |= DataAccountUsage::READ;
+ }
+ _ => (),
+ }
+
true
}
YulExpression::FunctionCall(..) => true,
diff --git a/src/sema/namespace.rs b/src/sema/namespace.rs
index 30e70827e..69504fc66 100644
--- a/src/sema/namespace.rs
+++ b/src/sema/namespace.rs
@@ -1498,6 +1498,7 @@ impl Namespace {
constant: true,
lvalue: false,
yul_function: false,
+ loop_nesting_level: 0,
};
let size_expr = expression(
@@ -1508,6 +1509,7 @@ impl Namespace {
diagnostics,
ResolveTo::Type(&Type::Uint(256)),
)?;
+ context.drop();
match size_expr.ty() {
Type::Uint(_) | Type::Int(_) => {}
diff --git a/src/sema/solana_accounts.rs b/src/sema/solana_accounts.rs
index 00f5a9c33..88c20036f 100644
--- a/src/sema/solana_accounts.rs
+++ b/src/sema/solana_accounts.rs
@@ -17,9 +17,9 @@ pub enum BuiltinAccounts {
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::SystemAccount => "systemProgram",
BuiltinAccounts::AssociatedTokenProgram => "associatedTokenProgram",
@@ -27,8 +27,13 @@ impl ToString for BuiltinAccounts {
BuiltinAccounts::TokenProgramId => "tokenProgram",
BuiltinAccounts::DataAccount => "dataAccount",
BuiltinAccounts::InstructionAccount => "SysvarInstruction",
- };
+ }
+ }
+}
+impl ToString for BuiltinAccounts {
+ fn to_string(&self) -> String {
+ let str = self.as_str();
str.to_string()
}
}
diff --git a/src/sema/statements.rs b/src/sema/statements.rs
index 991b46b0d..a03094cb3 100644
--- a/src/sema/statements.rs
+++ b/src/sema/statements.rs
@@ -41,7 +41,7 @@ pub fn resolve_function_body(
let mut symtable = Symtable::new();
let mut loops = LoopScopes::new();
let mut res = Vec::new();
- let context = ExprContext {
+ let mut context = ExprContext {
file_no,
contract_no,
function_no: Some(function_no),
@@ -49,6 +49,7 @@ pub fn resolve_function_body(
constant: false,
lvalue: false,
yul_function: false,
+ loop_nesting_level: 0,
};
let mut unresolved_annotation: Vec = Vec::new();
@@ -220,6 +221,7 @@ pub fn resolve_function_body(
}
}
+ context.drop();
ns.diagnostics.extend(diagnostics);
ns.functions[function_no].modifiers = modifiers;
}
@@ -285,7 +287,7 @@ pub fn resolve_function_body(
let reachable = statement(
body,
&mut res,
- &context,
+ &mut context,
&mut symtable,
&mut loops,
ns,
@@ -342,7 +344,7 @@ pub fn resolve_function_body(
fn statement(
stmt: &pt::Statement,
res: &mut Vec,
- context: &ExprContext,
+ context: &mut ExprContext,
symtable: &mut Symtable,
loops: &mut LoopScopes,
ns: &mut Namespace,
@@ -432,7 +434,7 @@ fn statement(
));
return Err(());
}
- reachable = statement(stmt, res, &context, symtable, loops, ns, diagnostics)?;
+ reachable = statement(stmt, res, &mut context, symtable, loops, ns, diagnostics)?;
}
symtable.leave_scope();
@@ -464,6 +466,7 @@ fn statement(
}
}
pt::Statement::While(loc, cond_expr, body) => {
+ context.enter_loop();
let expr = expression(
cond_expr,
context,
@@ -491,10 +494,11 @@ fn statement(
loops.leave_scope();
res.push(Statement::While(*loc, true, cond, body_stmts));
-
+ context.exit_loop();
Ok(true)
}
pt::Statement::DoWhile(loc, body, cond_expr) => {
+ context.enter_loop();
let expr = expression(
cond_expr,
context,
@@ -522,6 +526,7 @@ fn statement(
loops.leave_scope();
res.push(Statement::DoWhile(*loc, true, body_stmts, cond));
+ context.exit_loop();
Ok(true)
}
pt::Statement::If(loc, cond_expr, then, else_) => {
@@ -597,6 +602,7 @@ fn statement(
}
loops.new_scope();
+ context.enter_loop();
let mut body = Vec::new();
@@ -637,7 +643,7 @@ fn statement(
cond: None,
body,
});
-
+ context.exit_loop();
Ok(reachable)
}
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(
cond_expr,
context,
@@ -716,6 +723,7 @@ fn statement(
body,
});
+ context.exit_loop();
Ok(true)
}
pt::Statement::Return(loc, None) => {
@@ -2111,7 +2119,7 @@ fn try_catch(
expr: &pt::Expression,
returns_and_ok: &Option<(Vec<(pt::Loc, Option)>, Box)>,
clause_stmts: &[pt::CatchClause],
- context: &ExprContext,
+ context: &mut ExprContext,
symtable: &mut Symtable,
loops: &mut LoopScopes,
ns: &mut Namespace,
diff --git a/src/sema/tests/data_account.rs b/src/sema/tests/data_account.rs
new file mode 100644
index 000000000..b10dab299
--- /dev/null
+++ b/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
+ );
+}
diff --git a/src/sema/tests/mod.rs b/src/sema/tests/mod.rs
index c7b790a88..0c04d70a2 100644
--- a/src/sema/tests/mod.rs
+++ b/src/sema/tests/mod.rs
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
#![cfg(test)]
+
+mod data_account;
+
use crate::sema::ast::{Expression, Parameter, Statement, TryCatch, Type};
use crate::sema::yul::ast::InlineAssembly;
use crate::{parse_and_resolve, sema::ast, FileResolver, Target};
@@ -452,8 +455,8 @@ contract aborting {
}
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) {
// call succeeded; return values are in a and b
@@ -606,7 +609,7 @@ contract Child {
assert_eq!(errors.len(), 1);
assert_eq!(
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"
);
}
diff --git a/src/sema/unused_variable.rs b/src/sema/unused_variable.rs
index badf28f2b..b39dc576d 100644
--- a/src/sema/unused_variable.rs
+++ b/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 {
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 {
used_variable(ns, accounts.as_ref(), symtable);
}
diff --git a/src/sema/variables.rs b/src/sema/variables.rs
index 58c61dd28..d75c8bde3 100644
--- a/src/sema/variables.rs
+++ b/src/sema/variables.rs
@@ -326,6 +326,7 @@ pub fn variable_decl<'a>(
constant,
lvalue: false,
yul_function: false,
+ loop_nesting_level: 0,
};
match expression(
initializer,
@@ -782,12 +783,8 @@ pub fn resolve_initializers(
let context = ExprContext {
file_no,
- unchecked: false,
contract_no: Some(*contract_no),
- function_no: None,
- constant: false,
- lvalue: false,
- yul_function: false,
+ ..Default::default()
};
if let Ok(res) = expression(
@@ -803,6 +800,7 @@ pub fn resolve_initializers(
ns.contracts[*contract_no].variables[*var_no].initializer = Some(res);
}
}
+ context.drop();
}
ns.diagnostics.extend(diagnostics);
diff --git a/src/sema/yul/tests/expression.rs b/src/sema/yul/tests/expression.rs
index e1d78cb5a..c6141e468 100644
--- a/src/sema/yul/tests/expression.rs
+++ b/src/sema/yul/tests/expression.rs
@@ -23,15 +23,7 @@ use std::sync::Arc;
#[test]
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 function_table = FunctionsTable::new(0);
@@ -71,15 +63,7 @@ fn resolve_bool_literal() {
#[test]
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 function_table = FunctionsTable::new(0);
@@ -133,15 +117,7 @@ fn resolve_number_literal() {
#[test]
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 function_table = FunctionsTable::new(0);
@@ -184,15 +160,7 @@ fn resolve_hex_number_literal() {
#[test]
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 function_table = FunctionsTable::new(0);
@@ -255,15 +223,7 @@ fn resolve_hex_string_literal() {
#[test]
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 function_table = FunctionsTable::new(0);
@@ -292,15 +252,7 @@ fn resolve_string_literal() {
#[test]
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 function_table = FunctionsTable::new(0);
let mut ns = Namespace::new(Target::EVM);
@@ -378,6 +330,7 @@ fn resolve_variable_contract() {
constant: false,
lvalue: false,
yul_function: false,
+ loop_nesting_level: 0,
};
let mut symtable = Symtable::new();
let mut function_table = FunctionsTable::new(0);
@@ -530,15 +483,7 @@ fn resolve_variable_contract() {
#[test]
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 function_table = FunctionsTable::new(0);
function_table.new_scope();
@@ -691,15 +636,7 @@ fn function_call() {
#[test]
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 function_table = FunctionsTable::new(0);
function_table.new_scope();
@@ -840,7 +777,9 @@ fn test_member_access() {
constant: false,
lvalue: false,
yul_function: false,
+ loop_nesting_level: 0,
};
+
let mut symtable = Symtable::new();
let mut function_table = FunctionsTable::new(0);
let mut ns = Namespace::new(Target::EVM);
@@ -938,15 +877,7 @@ fn test_check_types() {
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 contract = ast::Contract::new("test", ContractTy::Contract(loc), vec![], loc);
diff --git a/stdlib/solana.c b/stdlib/solana.c
index 071b37da7..4001c6b4e 100644
--- a/stdlib/solana.c
+++ b/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
// 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];
SolInstruction instruction = {
@@ -72,62 +72,16 @@ uint64_t external_call(uint8_t *input, uint32_t input_len, SolPubkey *address, S
.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++)
{
SolAccountInfo *acc = ¶ms->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)
diff --git a/tests/codegen_testcases/solidity/constructor_with_metas.sol b/tests/codegen_testcases/solidity/constructor_with_metas.sol
index 8fb910fb5..c3060d08a 100644
--- a/tests/codegen_testcases/solidity/constructor_with_metas.sol
+++ b/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: 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();
}
@@ -21,7 +21,7 @@ contract creator {
contract Child {
@payer(payer)
@space(511 + 7)
- constructor(address payer) {
+ constructor() {
print("In child constructor");
}
diff --git a/tests/codegen_testcases/solidity/solana_bump.sol b/tests/codegen_testcases/solidity/solana_bump.sol
index 6402cde68..91be8f041 100644
--- a/tests/codegen_testcases/solidity/solana_bump.sol
+++ b/tests/codegen_testcases/solidity/solana_bump.sol
@@ -9,7 +9,7 @@ contract C1 {
}
// BEGIN-CHECK: solang_dispatch
// 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 {
@@ -23,7 +23,7 @@ contract C2 {
}
// BEGIN-CHECK: solang_dispatch
// 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 {
@@ -36,5 +36,5 @@ contract C3 {
}
// BEGIN-CHECK: solang_dispatch
// 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:
}
\ No newline at end of file
diff --git a/tests/codegen_testcases/solidity/solana_payer_account.sol b/tests/codegen_testcases/solidity/solana_payer_account.sol
index 56da9ead9..c4e59795c 100644
--- a/tests/codegen_testcases/solidity/solana_payer_account.sol
+++ b/tests/codegen_testcases/solidity/solana_payer_account.sol
@@ -3,13 +3,13 @@
@program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
contract Builder {
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!");
}
}
@@ -21,9 +21,10 @@ contract Built {
@payer(payer_account)
constructor(@seed bytes my_seed) {}
// 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
function say_this(string text) public pure {
diff --git a/tests/codegen_testcases/solidity/unused_variable_elimination.sol b/tests/codegen_testcases/solidity/unused_variable_elimination.sol
index 4c6b34212..b952580ae 100644
--- a/tests/codegen_testcases/solidity/unused_variable_elimination.sol
+++ b/tests/codegen_testcases/solidity/unused_variable_elimination.sol
@@ -214,7 +214,7 @@ contract c3 {
}
// BEGIN-CHECK: c3::function::test18
- function test18(address payable addr) public returns (bool) {
+ function test18(address payable addr) public payable returns (bool) {
bool p;
p = false || addr.send(msg.value);
// CHECK: value transfer address
diff --git a/tests/contract_testcases/solana/account_meta.sol b/tests/contract_testcases/solana/account_meta.sol
index c187423a0..9a7c7c756 100644
--- a/tests/contract_testcases/solana/account_meta.sol
+++ b/tests/contract_testcases/solana/account_meta.sol
@@ -18,5 +18,5 @@ contract spl {
}
// ---- 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'
diff --git a/tests/contract_testcases/solana/accounts/constructor_in_loop.sol b/tests/contract_testcases/solana/accounts/constructor_in_loop.sol
new file mode 100644
index 000000000..de1c502e0
--- /dev/null
+++ b/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
diff --git a/tests/contract_testcases/solana/accounts/data_account.sol b/tests/contract_testcases/solana/accounts/data_account.sol
new file mode 100644
index 000000000..7d3cfeff4
--- /dev/null
+++ b/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
diff --git a/tests/contract_testcases/solana/accounts/data_account_visibility.sol b/tests/contract_testcases/solana/accounts/data_account_visibility.sol
new file mode 100644
index 000000000..c39ddcd35
--- /dev/null
+++ b/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
\ No newline at end of file
diff --git a/tests/contract_testcases/solana/accounts/double_calls.sol b/tests/contract_testcases/solana/accounts/double_calls.sol
new file mode 100644
index 000000000..fb271704e
--- /dev/null
+++ b/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
diff --git a/tests/contract_testcases/solana/address_cast.sol b/tests/contract_testcases/solana/address_cast.sol
index ee6617814..bba23c1ae 100644
--- a/tests/contract_testcases/solana/address_cast.sol
+++ b/tests/contract_testcases/solana/address_cast.sol
@@ -3,7 +3,7 @@ contract c {
// We have code that cast address type to ref address
// in fn sema::cast(). Ensure that this does not cause
// address values to be assignable.
- address(0) = tx.program_id;
+ address(0) = address(this);
}
}
diff --git a/tests/contract_testcases/solana/annotations/account_name_collision.sol b/tests/contract_testcases/solana/annotations/account_name_collision.sol
index bbf2e24c9..1405b0a2e 100644
--- a/tests/contract_testcases/solana/annotations/account_name_collision.sol
+++ b/tests/contract_testcases/solana/annotations/account_name_collision.sol
@@ -3,8 +3,8 @@ contract Builder {
BeingBuilt other;
@payer(payer_account)
- constructor(address addr) {
- other = new BeingBuilt{address: addr}("abc");
+ constructor() {
+ other = new BeingBuilt("abc");
}
}
diff --git a/tests/contract_testcases/solana/annotations/constructor_external_function.sol b/tests/contract_testcases/solana/annotations/constructor_external_function.sol
index a3e37d39d..0f10ac5cd 100644
--- a/tests/contract_testcases/solana/annotations/constructor_external_function.sol
+++ b/tests/contract_testcases/solana/annotations/constructor_external_function.sol
@@ -9,13 +9,17 @@ contract Bar {
Foo public foo;
function external_create_foo(address addr) external {
- // This is allowed
+ // This not is allowed
foo = new Foo{address: addr}();
}
- function create_foo(address new_address) public {
+ function create_foo() public {
// 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 {
@@ -24,4 +28,5 @@ contract Bar {
}
// ---- 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
\ No newline at end of file
+// 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
diff --git a/tests/contract_testcases/solana/call/call_args_three_ways.sol b/tests/contract_testcases/solana/call/call_args_three_ways.sol
index 6a038c87c..8e92be1af 100644
--- a/tests/contract_testcases/solana/call/call_args_three_ways.sol
+++ b/tests/contract_testcases/solana/call/call_args_three_ways.sol
@@ -20,7 +20,7 @@ contract D {
}
// ---- 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: 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
diff --git a/tests/contract_testcases/solana/expressions/contract_no_init.sol b/tests/contract_testcases/solana/expressions/contract_no_init.sol
index 6bd8e521e..ca162c075 100644
--- a/tests/contract_testcases/solana/expressions/contract_no_init.sol
+++ b/tests/contract_testcases/solana/expressions/contract_no_init.sol
@@ -15,4 +15,4 @@
}
}
// ---- 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
diff --git a/tests/contract_testcases/solana/mapping_deletion.sol b/tests/contract_testcases/solana/mapping_deletion.sol
index 8e90f879c..327df92e1 100644
--- a/tests/contract_testcases/solana/mapping_deletion.sol
+++ b/tests/contract_testcases/solana/mapping_deletion.sol
@@ -19,7 +19,7 @@ contract DeleteTest {
mapping(uint => savedTest) example2;
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;
example[id] = dt;
savedTest tt = new savedTest(4);
@@ -39,4 +39,4 @@ contract DeleteTest {
}
// ---- Expect: diagnostics ----
-// error: 25:24-40: either 'address' or 'accounts' call argument is required on Solana
\ No newline at end of file
+// 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
diff --git a/tests/contract_testcases/solana/yul/yul_switch.sol b/tests/contract_testcases/solana/yul/yul_switch.sol
index 968c4ebad..aa8bc5a88 100644
--- a/tests/contract_testcases/solana/yul/yul_switch.sol
+++ b/tests/contract_testcases/solana/yul/yul_switch.sol
@@ -1,6 +1,6 @@
contract testTypes {
uint256 b;
- function testAsm(uint128[] calldata vl) public pure returns (uint256) {
+ function testAsm(uint128[] calldata vl) public view returns (uint256) {
uint256 y = 0;
assembly {
switch vl.length
@@ -17,3 +17,4 @@ contract testTypes {
}
}
// ---- Expect: diagnostics ----
+// warning: 3:5-74: function declared 'view' can be declared 'pure'
\ No newline at end of file
diff --git a/tests/imports_testcases/Dummy.json b/tests/imports_testcases/Dummy.json
new file mode 100644
index 000000000..6a23f6aaa
--- /dev/null
+++ b/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": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol b/tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol
index e00dd56a2..2149254d4 100644
--- a/tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol
+++ b/tests/optimization_testcases/programs/f46807c38c2116c0f3192e9a8d2bede4f34846d2.sol
@@ -17,7 +17,7 @@ contract c {
for (uint32 i = 0; i < tx.accounts.length; 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);
}
}
diff --git a/tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol b/tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol
index d3142dd35..3ab322486 100644
--- a/tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol
+++ b/tests/optimization_testcases/programs/f646b924357689419072fddf402c3ad3c10cd095.sol
@@ -9,7 +9,7 @@ contract foo {
function test2() public returns (bytes) {
bytes bs = new bytes(34);
bs.writeUint16LE(0x4142, 0);
- bs.writeAddress(tx.program_id, 2);
+ bs.writeAddress(address(this), 2);
return bs;
}
diff --git a/tests/polkadot_tests/calls.rs b/tests/polkadot_tests/calls.rs
index 14f87058b..d0bee1ecd 100644
--- a/tests/polkadot_tests/calls.rs
+++ b/tests/polkadot_tests/calls.rs
@@ -295,7 +295,7 @@ fn try_catch_external_calls() {
return c.get_a();
}
- function test() public pure returns (int32) {
+ function test() public returns (int32) {
try c.go_bang() returns (int32 l) {
print("try call success");
return 8000;
diff --git a/tests/polkadot_tests/contracts.rs b/tests/polkadot_tests/contracts.rs
index eb0bd3281..ddd6844d1 100644
--- a/tests/polkadot_tests/contracts.rs
+++ b/tests/polkadot_tests/contracts.rs
@@ -205,7 +205,7 @@ fn issue666() {
_flipper = _flipperContract;
}
- function superFlip () pure public {
+ function superFlip () view public {
_flipper.flip();
}
}"#,
diff --git a/tests/polkadot_tests/yul.rs b/tests/polkadot_tests/yul.rs
index ef6858e6f..3844658b4 100644
--- a/tests/polkadot_tests/yul.rs
+++ b/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 {
vec.offset := add(input, 7)
input := 9
diff --git a/tests/solana.rs b/tests/solana.rs
index 8da8bb854..b2f3f0f57 100644
--- a/tests/solana.rs
+++ b/tests/solana.rs
@@ -1667,7 +1667,7 @@ impl<'a, 'b> VmFunction<'a, 'b> {
accounts
.get(account.name.as_str())
.cloned()
- .expect("an account is missing"),
+ .unwrap_or_else(|| panic!("account '{}' is missing", account.name)),
),
is_writable: account.is_mut,
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
}
diff --git a/tests/solana_tests/abi.rs b/tests/solana_tests/abi.rs
index 12415a61a..880a16cf0 100644
--- a/tests/solana_tests/abi.rs
+++ b/tests/solana_tests/abi.rs
@@ -51,21 +51,13 @@ fn packed() {
.accounts(vec![("dataAccount", account)])
.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]
@@ -85,9 +77,7 @@ fn inherited() {
.accounts(vec![("dataAccount", data_account)])
.call();
- vm.function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ vm.function("test").call();
let mut vm = build_solidity(
r#"
diff --git a/tests/solana_tests/abi_decode.rs b/tests/solana_tests/abi_decode.rs
index 3f80af8f7..08c1270b8 100644
--- a/tests/solana_tests/abi_decode.rs
+++ b/tests/solana_tests/abi_decode.rs
@@ -125,14 +125,13 @@ fn decode_address() {
.call();
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 _ = vm
.function("testAddress")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -169,7 +168,6 @@ fn string_and_bytes() {
let _ = vm
.function("testStringAndBytes")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -633,7 +631,6 @@ fn arrays() {
let _ = vm
.function("decodeComplex")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
let input = Input2 {
@@ -643,7 +640,6 @@ fn arrays() {
let _ = vm
.function("dynamicArray")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
let input = Input3 {
@@ -653,7 +649,6 @@ fn arrays() {
let _ = vm
.function("decodeMultiDim")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -920,7 +915,6 @@ fn external_function() {
let returns = vm
.function("testExternalFunction")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -969,7 +963,6 @@ fn bytes_arrays() {
let _ = vm
.function("testByteArrays")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -1008,7 +1001,6 @@ fn different_types() {
let _ = vm
.function("testByteArrays")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -1042,7 +1034,6 @@ fn more_elements() {
let _ = vm
.function("wrongNumber")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -1149,7 +1140,6 @@ fn longer_buffer() {
let _ = vm
.function("testLongerBuffer")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -1188,7 +1178,6 @@ fn longer_buffer_array() {
let _ = vm
.function("testLongerBuffer")
.arguments(&[BorshToken::Bytes(encoded)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
diff --git a/tests/solana_tests/abi_encode.rs b/tests/solana_tests/abi_encode.rs
index 4ad751f85..a7244efbe 100644
--- a/tests/solana_tests/abi_encode.rs
+++ b/tests/solana_tests/abi_encode.rs
@@ -115,15 +115,11 @@ contract Testing {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.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 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]
@@ -526,11 +522,7 @@ fn struct_in_array() {
assert_eq!(decoded.item_3[0], NoPadStruct { a: 1, b: 2 });
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 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[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 decoded = Res2::try_from_slice(&encoded).unwrap();
@@ -911,12 +899,7 @@ fn external_function() {
.accounts(vec![("dataAccount", data_account)])
.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 decoded = Res::try_from_slice(&encoded).unwrap();
@@ -1032,11 +1015,12 @@ contract caller {
.accounts(vec![("dataAccount", data_account)])
.call();
+ let caller_program_id = vm.stack[0].id;
let returns = vm
.function("do_call")
.accounts(vec![
- ("dataAccount", data_account),
("systemProgram", [0; 32]),
+ ("caller_programId", caller_program_id),
])
.call()
.unwrap()
diff --git a/tests/solana_tests/accessor.rs b/tests/solana_tests/accessor.rs
index b4b1b0980..6efcbb39d 100644
--- a/tests/solana_tests/accessor.rs
+++ b/tests/solana_tests/accessor.rs
@@ -183,11 +183,7 @@ fn constant() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("z")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("z").call().unwrap();
assert_eq!(
returns,
@@ -209,11 +205,7 @@ fn constant() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("z")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("z").call().unwrap();
assert_eq!(
returns,
@@ -235,11 +227,7 @@ fn constant() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("z")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("z").call().unwrap();
assert_eq!(
returns,
@@ -254,6 +242,7 @@ fn constant() {
fn struct_accessor() {
let mut vm = build_solidity(
r#"
+ import 'solana';
contract C {
struct E {
bytes4 b4;
@@ -274,13 +263,16 @@ fn struct_accessor() {
}
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");
- (a1, b, c) = this.s(99);
+ (a1, b, c) = this.s{accounts: meta}(99);
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");
- c.b4 = this.e();
+ c.b4 = this.e{accounts: meta}();
require(a1 == 414243 && b && c.b4 == "cons", "E");
}
}"#,
diff --git a/tests/solana_tests/account_info.rs b/tests/solana_tests/account_info.rs
index c1f92fff5..2d3d16109 100644
--- a/tests/solana_tests/account_info.rs
+++ b/tests/solana_tests/account_info.rs
@@ -45,7 +45,6 @@ fn lamports() {
let returns = vm
.function("test")
.arguments(&[BorshToken::Address(acc)])
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(acc),
is_writable: true,
@@ -70,15 +69,7 @@ fn owner() {
import 'solana';
contract c {
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';
contract c {
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) {
- 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 {
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;
acc2.lamports = lamport2;
@@ -272,7 +248,6 @@ contract starter {
value: BigInt::from(9u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&metas)
.call();
@@ -289,7 +264,7 @@ import 'solana';
contract C {
function test() external {
- AccountInfo ai = tx.accounts[1];
+ AccountInfo ai = tx.accounts[0];
ai.data[0] = 0xca;
ai.data[1] = 0xff;
ai.data[2] = 0xee;
@@ -315,7 +290,6 @@ contract C {
);
vm.function("test")
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(other_account),
is_writable: true,
diff --git a/tests/solana_tests/account_serialization.rs b/tests/solana_tests/account_serialization.rs
index 79a4bfbfc..c00487da1 100644
--- a/tests/solana_tests/account_serialization.rs
+++ b/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_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")
- .arguments(&[BorshToken::Address(program_id)])
+ .arguments(&[BorshToken::Address(data_account)])
.accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&[
AccountMeta {
@@ -71,7 +70,7 @@ fn more_than_10_accounts() {
function check_deserialization(address my_address) public view {
// This assertion ensure the padding is correctly added when
// 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;
vm.function("check_deserialization")
.arguments(&[BorshToken::Address(program_id)])
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&metas)
.call();
}
diff --git a/tests/solana_tests/arrays.rs b/tests/solana_tests/arrays.rs
index dbfe2072c..f751b9c23 100644
--- a/tests/solana_tests/arrays.rs
+++ b/tests/solana_tests/arrays.rs
@@ -25,12 +25,7 @@ fn fixed_array() {
.accounts(vec![("dataAccount", data_account)])
.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!(
returns,
@@ -79,11 +74,7 @@ fn fixed_array() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("get")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("get").call().unwrap();
assert_eq!(
returns,
@@ -155,11 +146,7 @@ fn fixed_array() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("get")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("get").call().unwrap();
assert_eq!(
returns,
@@ -211,7 +198,6 @@ fn fixed_array() {
]),
BorshToken::Bool(true),
])])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -287,7 +273,6 @@ fn dynamic_array_fixed_elements() {
value: BigInt::from(102u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -300,12 +285,7 @@ fn dynamic_array_fixed_elements() {
);
// 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!(
returns,
@@ -391,7 +371,6 @@ fn fixed_array_dynamic_elements() {
value: BigInt::from(102u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.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!(
returns,
@@ -486,7 +460,6 @@ fn dynamic_array_dynamic_elements() {
value: BigInt::from(102u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.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!(
returns,
@@ -1754,10 +1722,7 @@ fn dynamic_array_push() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -1783,10 +1748,7 @@ fn dynamic_array_push() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -1817,10 +1779,7 @@ fn dynamic_array_push() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -1847,10 +1806,7 @@ fn dynamic_array_push() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
// push() returns a reference to the thing
let mut runtime = build_solidity(
@@ -1881,10 +1837,7 @@ fn dynamic_array_push() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
}
#[test]
@@ -1913,10 +1866,7 @@ fn dynamic_array_pop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -1942,10 +1892,7 @@ fn dynamic_array_pop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -1978,10 +1925,7 @@ fn dynamic_array_pop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -2008,10 +1952,7 @@ fn dynamic_array_pop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
}
#[test]
@@ -2113,10 +2054,7 @@ fn dynamic_array_push_pop_loop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -2160,10 +2098,7 @@ fn dynamic_array_push_pop_loop() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
}
#[test]
diff --git a/tests/solana_tests/balance.rs b/tests/solana_tests/balance.rs
index d4a224b58..fa096a8ff 100644
--- a/tests/solana_tests/balance.rs
+++ b/tests/solana_tests/balance.rs
@@ -34,12 +34,18 @@ fn get_balance() {
let returns = vm
.function("test")
.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()
.unwrap();
@@ -88,12 +94,18 @@ fn send_fails() {
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()
.unwrap();
@@ -140,12 +152,18 @@ fn send_succeeds() {
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()
.unwrap();
@@ -195,12 +213,18 @@ fn send_overflows() {
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()
.unwrap();
@@ -254,12 +278,18 @@ fn transfer_succeeds() {
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();
assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
@@ -305,12 +335,18 @@ fn transfer_fails_not_enough() {
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();
assert!(res.is_err());
@@ -326,12 +362,18 @@ fn transfer_fails_not_enough() {
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();
assert_eq!(vm.account_data[&data_account].lamports, 0);
@@ -378,12 +420,18 @@ fn transfer_fails_overflow() {
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();
assert!(res.is_err());
@@ -399,12 +447,18 @@ fn transfer_fails_overflow() {
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();
assert_eq!(vm.account_data[&new].lamports, u64::MAX);
@@ -486,12 +540,18 @@ fn value_overflows() {
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();
assert_eq!(res.unwrap(), 4294967296);
@@ -504,12 +564,18 @@ fn value_overflows() {
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();
assert_eq!(res.unwrap(), 4294967296);
@@ -523,12 +589,18 @@ fn value_overflows() {
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()
.unwrap();
diff --git a/tests/solana_tests/builtin.rs b/tests/solana_tests/builtin.rs
index 4449c0797..7342f29d2 100644
--- a/tests/solana_tests/builtin.rs
+++ b/tests/solana_tests/builtin.rs
@@ -25,7 +25,7 @@ fn builtins() {
return msg.sig;
}
function prog() public returns (address) {
- return tx.program_id;
+ return address(this);
}
}"#,
);
@@ -43,10 +43,7 @@ fn builtins() {
.unwrap();
let returns = vm
.function("mr_now")
- .accounts(vec![
- ("dataAccount", data_account),
- ("clock", clock_account),
- ])
+ .accounts(vec![("clock", clock_account)])
.call()
.unwrap();
@@ -60,10 +57,7 @@ fn builtins() {
let returns = vm
.function("mr_slot")
- .accounts(vec![
- ("dataAccount", data_account),
- ("clock", clock_account),
- ])
+ .accounts(vec![("clock", clock_account)])
.call()
.unwrap();
@@ -77,10 +71,7 @@ fn builtins() {
let returns = vm
.function("mr_blocknumber")
- .accounts(vec![
- ("dataAccount", data_account),
- ("clock", clock_account),
- ])
+ .accounts(vec![("clock", clock_account)])
.call()
.unwrap();
@@ -98,7 +89,6 @@ fn builtins() {
width: 32,
value: BigInt::from(0xdeadcafeu32),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -111,11 +101,7 @@ fn builtins() {
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() {
println!("{}", hex::encode(v));
@@ -126,11 +112,7 @@ fn builtins() {
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));
}
@@ -179,10 +161,7 @@ fn pda() {
let returns = vm
.function("create_pda")
.arguments(&[BorshToken::Bool(true)])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
@@ -198,10 +177,7 @@ fn pda() {
let returns = vm
.function("create_pda")
.arguments(&[BorshToken::Bool(false)])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
@@ -220,10 +196,7 @@ fn pda() {
BorshToken::Bytes(b"Talking".to_vec()),
BorshToken::Bytes(b"Squirrels".to_vec()),
])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
@@ -239,7 +212,6 @@ fn pda() {
let returns = vm
.function("create_pda2_bump")
.arguments(&[BorshToken::Bool(true)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -258,7 +230,6 @@ fn pda() {
let returns = vm
.function("create_pda2_bump")
.arguments(&[BorshToken::Bool(false)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
diff --git a/tests/solana_tests/call.rs b/tests/solana_tests/call.rs
index aa037b678..90c5a1499 100644
--- a/tests/solana_tests/call.rs
+++ b/tests/solana_tests/call.rs
@@ -4,7 +4,7 @@ use crate::{
build_solidity, create_program_address, AccountMeta, AccountState, BorshToken, Instruction,
Pubkey, VirtualMachine,
};
-use base58::FromBase58;
+use base58::{FromBase58, ToBase58};
use num_bigint::BigInt;
use num_traits::One;
@@ -36,7 +36,6 @@ fn simple_external_call() {
.call();
vm.function("test_bar")
- .accounts(vec![("dataAccount", bar1_account)])
.arguments(&[BorshToken::String(String::from("yo"))])
.call();
@@ -52,7 +51,6 @@ fn simple_external_call() {
.call();
vm.function("test_bar")
- .accounts(vec![("dataAccount", bar0_account)])
.arguments(&[BorshToken::String(String::from("uncle beau"))])
.call();
@@ -62,7 +60,7 @@ fn simple_external_call() {
vm.function("test_other")
.accounts(vec![
- ("dataAccount", bar0_account),
+ ("bar1_programId", bar1_program_id),
("systemProgram", [0; 32]),
])
.remaining_accounts(&[
@@ -77,7 +75,7 @@ fn simple_external_call() {
is_writable: false,
},
])
- .arguments(&[BorshToken::Address(bar1_account)])
+ .arguments(&[BorshToken::Address(bar1_program_id)])
.call();
assert_eq!(vm.logs, "bar1 says: cross contract call");
@@ -108,7 +106,6 @@ fn external_call_with_returns() {
let res = vm
.function("test_bar")
- .accounts(vec![("dataAccount", bar1_account)])
.arguments(&[BorshToken::Int {
width: 64,
value: BigInt::from(21),
@@ -133,9 +130,9 @@ fn external_call_with_returns() {
let res = vm
.function("test_other")
- .arguments(&[BorshToken::Address(bar1_account)])
+ .arguments(&[BorshToken::Address(bar1_program_id)])
.accounts(vec![
- ("dataAccount", bar0_account),
+ ("bar1_programId", bar1_program_id),
("systemProgram", [0; 32]),
])
.remaining_accounts(&[
@@ -198,7 +195,6 @@ fn external_raw_call_with_returns() {
width: 64,
value: BigInt::from(21u8),
}])
- .accounts(vec![("dataAccount", bar1_account)])
.call()
.unwrap();
@@ -219,11 +215,8 @@ fn external_raw_call_with_returns() {
let res = vm
.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(&[
AccountMeta {
pubkey: Pubkey(bar1_account),
@@ -275,10 +268,7 @@ fn call_external_func_type() {
let res = vm
.function("doTest")
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap()
.unwrap_tuple();
@@ -338,7 +328,6 @@ fn external_call_with_string_returns() {
width: 64,
value: BigInt::from(22u8),
}])
- .accounts(vec![("dataAccount", bar1_account)])
.call()
.unwrap();
@@ -353,9 +342,9 @@ fn external_call_with_string_returns() {
let res = vm
.function("test_other")
- .arguments(&[BorshToken::Address(bar1_account)])
+ .arguments(&[BorshToken::Address(bar1_program_id)])
.accounts(vec![
- ("dataAccount", bar0_account),
+ ("bar1_programId", bar1_program_id),
("systemProgram", [0; 32]),
])
.remaining_accounts(&[
@@ -376,9 +365,9 @@ fn external_call_with_string_returns() {
assert_eq!(res, BorshToken::String(String::from("foo:7")));
vm.function("test_this")
- .arguments(&[BorshToken::Address(bar1_account)])
+ .arguments(&[BorshToken::Address(bar1_program_id)])
.accounts(vec![
- ("dataAccount", bar0_account),
+ ("bar1_programId", bar1_program_id),
("systemProgram", [0; 32]),
])
.remaining_accounts(&[
@@ -414,7 +403,7 @@ fn encode_call() {
}
contract bar1 {
- function test_bar(int64 y) public returns (int64) {
+ function test_bar(int64 y) public pure returns (int64) {
return 3 + y;
}
}"#,
@@ -432,7 +421,6 @@ fn encode_call() {
width: 64,
value: BigInt::from(21u8),
}])
- .accounts(vec![("dataAccount", bar1_account)])
.call()
.unwrap();
@@ -451,13 +439,11 @@ fn encode_call() {
.accounts(vec![("dataAccount", bar0_account)])
.call();
+ std::println!("bar_acc: {}", bar1_account.to_base58());
let res = vm
.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(&[
AccountMeta {
pubkey: Pubkey(bar1_account),
@@ -677,11 +663,7 @@ fn raw_call_accounts() {
BorshToken::Address(b"quinquagintaquadringentilliardth".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();
}
@@ -749,10 +731,6 @@ fn pda() {
vm.call_params_check.insert(token.clone(), test_args);
vm.function("test")
- .accounts(vec![
- ("dataAccount", data_account),
- ("tokenProgram", token.0),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("tokenProgram", token.0), ("systemProgram", [0; 32])])
.call();
}
diff --git a/tests/solana_tests/constant.rs b/tests/solana_tests/constant.rs
index 63b7cdd07..3718662c7 100644
--- a/tests/solana_tests/constant.rs
+++ b/tests/solana_tests/constant.rs
@@ -25,11 +25,7 @@ fn constant() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("f").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -58,11 +54,7 @@ fn constant() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("f").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
diff --git a/tests/solana_tests/create_contract.rs b/tests/solana_tests/create_contract.rs
index 749f86ecc..0a6a5dfaf 100644
--- a/tests/solana_tests/create_contract.rs
+++ b/tests/solana_tests/create_contract.rs
@@ -11,8 +11,8 @@ fn simple_create_contract_no_seed() {
let mut vm = build_solidity(
r#"
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;
}
@@ -65,9 +65,9 @@ fn simple_create_contract_no_seed() {
let bar1 = vm
.function("test_other")
- .arguments(&[BorshToken::Address(acc)])
.accounts(vec![
- ("dataAccount", data_account),
+ ("bar1_dataAccount", acc),
+ ("bar1_programId", program_id),
("payer", payer),
("systemProgram", [0; 32]),
])
@@ -88,21 +88,9 @@ fn simple_create_contract_no_seed() {
vm.function("call_bar1_at_address")
.arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
.accounts(vec![
- ("dataAccount", data_account),
+ ("bar1_programId", program_id),
("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();
assert_eq!(vm.logs, "Hello xywoleh");
@@ -113,8 +101,8 @@ fn simple_create_contract() {
let mut vm = build_solidity(
r#"
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;
}
@@ -156,17 +144,12 @@ fn simple_create_contract() {
let bar1 = vm
.function("test_other")
- .arguments(&[BorshToken::Address(seed.0)])
.accounts(vec![
- ("dataAccount", data_account),
+ ("bar1_dataAccount", seed.0),
+ ("bar1_programId", program_id),
("pay", payer),
("systemProgram", [0; 32]),
])
- .remaining_accounts(&[AccountMeta {
- pubkey: Pubkey(seed.0),
- is_signer: false,
- is_writable: true,
- }])
.call()
.unwrap();
@@ -179,21 +162,9 @@ fn simple_create_contract() {
vm.function("call_bar1_at_address")
.arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
.accounts(vec![
- ("dataAccount", data_account),
+ ("bar1_programId", program_id),
("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();
assert_eq!(vm.logs, "Hello xywoleh");
@@ -309,8 +280,8 @@ fn missing_contract() {
let mut vm = build_solidity(
r#"
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;
}
@@ -341,6 +312,7 @@ fn missing_contract() {
let missing = account_new();
vm.logs.clear();
vm.account_data.insert(missing, AccountState::default());
+
let program_id: Account = "7vJKRaKLGCNUPuHWdeHCTknkYf3dHXXEZ6ri7dc6ngeV"
.from_base58()
.unwrap()
@@ -350,23 +322,11 @@ fn missing_contract() {
// There is no payer account, so the external call fails.
let _ = vm
.function("test_other")
- .arguments(&[BorshToken::Address(missing)])
.accounts(vec![
- ("dataAccount", data_account),
+ ("bar1_programId", program_id),
+ ("bar1_dataAccount", missing),
("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();
}
@@ -374,10 +334,20 @@ fn missing_contract() {
fn two_contracts() {
let mut vm = build_solidity(
r#"
+ import 'solana';
+
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;
}
@@ -407,18 +377,19 @@ fn two_contracts() {
let seed1 = vm.create_pda(&program_id, 5);
let seed2 = vm.create_pda(&program_id, 5);
let payer = account_new();
+
vm.account_data.insert(seed1.0, AccountState::default());
vm.account_data.insert(seed2.0, AccountState::default());
vm.account_data.insert(payer, AccountState::default());
let _bar1 = vm
.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(&[
AccountMeta {
pubkey: Pubkey(seed1.0),
@@ -435,6 +406,11 @@ fn two_contracts() {
is_writable: false,
is_signer: false,
},
+ AccountMeta {
+ pubkey: Pubkey(payer),
+ is_signer: true,
+ is_writable: true,
+ },
])
.call();
@@ -507,11 +483,7 @@ fn account_with_space() {
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));
}
@@ -552,11 +524,7 @@ fn account_with_seed() {
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));
}
@@ -607,11 +575,7 @@ fn account_with_seed_bump() {
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));
}
@@ -655,11 +619,7 @@ fn account_with_seed_bump_literals() {
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));
}
@@ -671,10 +631,9 @@ fn create_child() {
contract creator {
Child public c;
- function create_child(address child) external {
+ function create_child() external {
print("Going to create child");
- c = new Child{address: child}();
-
+ c = new Child();
c.say_hello();
}
}
@@ -699,6 +658,12 @@ fn create_child() {
.accounts(vec![("dataAccount", data_account)])
.call();
+ let child_program_id: Account = "Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT"
+ .from_base58()
+ .unwrap()
+ .try_into()
+ .unwrap();
+
let payer = account_new();
let program_id = vm.stack[0].id;
@@ -707,8 +672,9 @@ fn create_child() {
vm.account_data.insert(seed.0, AccountState::default());
vm.function("create_child")
- .arguments(&[BorshToken::Address(seed.0)])
.accounts(vec![
+ ("Child_dataAccount", seed.0),
+ ("Child_programId", child_program_id),
("dataAccount", data_account),
("payer", payer),
("systemProgram", [0; 32]),
@@ -774,9 +740,16 @@ contract Child {
vm.account_data.insert(seed.0, 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")
.arguments(&[BorshToken::Address(seed.0), BorshToken::Address(payer)])
.accounts(vec![
+ ("Child_programId", child_program_id),
("dataAccount", data_account),
("systemProgram", [0; 32]),
])
diff --git a/tests/solana_tests/destructure.rs b/tests/solana_tests/destructure.rs
index 6a627904f..a5b5bdeda 100644
--- a/tests/solana_tests/destructure.rs
+++ b/tests/solana_tests/destructure.rs
@@ -26,7 +26,6 @@ fn conditional_destructure() {
let returns = vm
.function("f")
.arguments(&[BorshToken::Bool(true), BorshToken::Bool(true)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -48,7 +47,6 @@ fn conditional_destructure() {
let returns = vm
.function("f")
.arguments(&[BorshToken::Bool(true), BorshToken::Bool(false)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -70,7 +68,6 @@ fn conditional_destructure() {
let returns = vm
.function("f")
.arguments(&[BorshToken::Bool(false), BorshToken::Bool(false)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -92,7 +89,6 @@ fn conditional_destructure() {
let returns = vm
.function("f")
.arguments(&[BorshToken::Bool(false), BorshToken::Bool(true)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -169,11 +165,7 @@ fn casting_destructure() {
.accounts(vec![("dataAccount", data_account)])
.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")));
}
diff --git a/tests/solana_tests/events.rs b/tests/solana_tests/events.rs
index 6dbedb75a..d817dba05 100644
--- a/tests/solana_tests/events.rs
+++ b/tests/solana_tests/events.rs
@@ -28,9 +28,7 @@ fn simple_event() {
.accounts(vec![("dataAccount", data_account)])
.call();
- vm.function("go")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ vm.function("go").call();
assert_eq!(vm.events.len(), 1);
assert_eq!(vm.events[0].len(), 1);
@@ -87,9 +85,7 @@ fn less_simple_event() {
.accounts(vec![("dataAccount", data_account)])
.call();
- vm.function("go")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ vm.function("go").call();
assert_eq!(vm.events.len(), 1);
assert_eq!(vm.events[0].len(), 1);
diff --git a/tests/solana_tests/expressions.rs b/tests/solana_tests/expressions.rs
index 2c05f142c..e2a7e5b9f 100644
--- a/tests/solana_tests/expressions.rs
+++ b/tests/solana_tests/expressions.rs
@@ -25,11 +25,7 @@ fn interfaceid() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("get")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("get").call().unwrap();
assert_eq!(
returns,
@@ -52,7 +48,7 @@ fn write_buffer() {
function test2() public returns (bytes) {
bytes bs = new bytes(34);
bs.writeUint16LE(0x4142, 0);
- bs.writeAddress(tx.program_id, 2);
+ bs.writeAddress(address(this), 2);
return bs;
}
@@ -69,32 +65,21 @@ fn write_buffer() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test1")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test1").call().unwrap();
assert_eq!(
returns,
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];
buf.extend_from_slice(&vm.stack[0].id);
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);
}
@@ -123,7 +108,6 @@ fn read_buffer() {
.arguments(&[BorshToken::Bytes(
[0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(),
)])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -147,7 +131,6 @@ fn read_buffer() {
.arguments(&[BorshToken::Bytes(
[0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2].to_vec(),
)])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(res.unwrap(), 4294967296);
@@ -158,7 +141,6 @@ fn read_buffer() {
let returns = vm
.function("test2")
.arguments(&[BorshToken::Bytes(buf.clone())])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -179,7 +161,6 @@ fn read_buffer() {
let res = vm
.function("test2")
.arguments(&[BorshToken::Bytes(buf)])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(res.unwrap(), 4294967296);
}
@@ -207,7 +188,6 @@ fn bytes_compare() {
let returns = vm
.function("test1")
.arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -216,7 +196,6 @@ fn bytes_compare() {
let returns = vm
.function("test2")
.arguments(&[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
diff --git a/tests/solana_tests/hash.rs b/tests/solana_tests/hash.rs
index ffb5a0de4..a87b981bf 100644
--- a/tests/solana_tests/hash.rs
+++ b/tests/solana_tests/hash.rs
@@ -21,10 +21,7 @@ fn constants_hash_tests() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -42,10 +39,7 @@ fn constants_hash_tests() {
.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
let mut runtime = build_solidity(
r#"
@@ -63,10 +57,7 @@ fn constants_hash_tests() {
.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
}
#[test]
@@ -90,10 +81,7 @@ fn hash_tests() {
let hash = runtime
.function("test")
.arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
@@ -123,10 +111,7 @@ fn hash_tests() {
let hash = runtime
.function("test")
.arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
@@ -157,10 +142,7 @@ fn hash_tests() {
let hash = runtime
.function("test")
.arguments(&[BorshToken::Bytes(b"Hello, World!".to_vec())])
- .accounts(vec![
- ("dataAccount", data_account),
- ("systemProgram", [0; 32]),
- ])
+ .accounts(vec![("systemProgram", [0; 32])])
.call()
.unwrap();
diff --git a/tests/solana_tests/math.rs b/tests/solana_tests/math.rs
index 9f83415f2..57944ee93 100644
--- a/tests/solana_tests/math.rs
+++ b/tests/solana_tests/math.rs
@@ -56,7 +56,6 @@ fn safe_math() {
value: BigInt::from_str("4000000000000000000").unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -80,7 +79,6 @@ fn safe_math() {
value: BigInt::from_str("4000000000000000000").unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -104,7 +102,6 @@ fn safe_math() {
value: BigInt::from_str("1000000000000000000").unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -127,7 +124,6 @@ fn safe_math() {
value: BigInt::from_str("400000000000000000000000000000000000000").unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
vm.function(
@@ -144,7 +140,6 @@ fn safe_math() {
},
],
)
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
vm.function("sub_test")
@@ -158,6 +153,5 @@ fn safe_math() {
value: BigInt::from_str("4000000000000000000").unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
}
diff --git a/tests/solana_tests/metas.rs b/tests/solana_tests/metas.rs
index d3c00b45a..fb2057c48 100644
--- a/tests/solana_tests/metas.rs
+++ b/tests/solana_tests/metas.rs
@@ -141,7 +141,6 @@ contract Foo {
let res = vm
.function("token_account")
.arguments(&[BorshToken::Address(account)])
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(account),
is_signer: false,
@@ -190,7 +189,6 @@ contract Foo {
let res = vm
.function("token_account")
.arguments(&[BorshToken::Address(account)])
- .accounts(vec![("dataAccount", data_account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(account),
is_signer: false,
@@ -289,7 +287,6 @@ contract Foo {
let res = vm
.function("mint_account")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::Address(account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(account),
@@ -327,7 +324,6 @@ contract Foo {
let res = vm
.function("mint_account")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::Address(account)])
.remaining_accounts(&[AccountMeta {
pubkey: Pubkey(account),
diff --git a/tests/solana_tests/optimizations.rs b/tests/solana_tests/optimizations.rs
index 9cc171fca..592da99ba 100644
--- a/tests/solana_tests/optimizations.rs
+++ b/tests/solana_tests/optimizations.rs
@@ -2,10 +2,12 @@
use crate::{
borsh_encoding::{visit_mut, VisitorMut},
- BorshToken, VirtualMachineBuilder,
+ AccountMeta, BorshToken, Pubkey, VirtualMachineBuilder,
};
+use anchor_syn::idl::IdlAccountItem;
use once_cell::sync::Lazy;
-use rayon::prelude::*;
+use rayon::iter::ParallelIterator;
+use rayon::prelude::IntoParallelIterator;
use serde::Deserialize;
use solang::codegen::Options;
use std::{
@@ -42,6 +44,7 @@ fn optimizations() {
.map(|entry| entry.unwrap().path())
.collect::>();
tests.into_par_iter().for_each(|path| run_test(&path));
+ //tests.iter().for_each(|path| run_test(path));
}
}
@@ -91,13 +94,38 @@ fn run_test_with_opts>(program: &str, calls: &Ca
.call_with_error_code(),
);
+ let program_id = vm.stack[0].id;
for (name, args) in &calls.function {
- results_curr.push(
+ let needs_account = vm.stack[0]
+ .idl
+ .as_ref()
+ .unwrap()
+ .instructions
+ .iter()
+ .find(|instr| &instr.name == name)
+ .unwrap()
+ .accounts
+ .iter()
+ .any(|acc| match acc {
+ IdlAccountItem::IdlAccount(account) => account.name == "dataAccount",
+ IdlAccountItem::IdlAccounts(_) => false,
+ });
+
+ results_curr.push(if needs_account {
vm.function(name)
.arguments(args)
.accounts(vec![("dataAccount", data_account)])
- .call_with_error_code(),
- );
+ .call_with_error_code()
+ } else {
+ vm.function(name)
+ .arguments(args)
+ .remaining_accounts(&[AccountMeta {
+ pubkey: Pubkey(program_id),
+ is_signer: false,
+ is_writable: false,
+ }])
+ .call_with_error_code()
+ });
}
for token in results_curr.iter_mut().flatten().flatten() {
diff --git a/tests/solana_tests/primitives.rs b/tests/solana_tests/primitives.rs
index 1fb64f91e..10537adab 100644
--- a/tests/solana_tests/primitives.rs
+++ b/tests/solana_tests/primitives.rs
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
-use crate::{build_solidity, BorshToken};
+use crate::{build_solidity, Account, BorshToken};
+use base58::FromBase58;
use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
use num_traits::{One, Pow, ToPrimitive, Zero};
use rand::seq::SliceRandom;
@@ -54,9 +55,7 @@ fn assert_true() {
.accounts(vec![("dataAccount", data_account)])
.call();
- vm.function("assert_fails")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ vm.function("assert_fails").call();
}
#[test]
@@ -91,29 +90,19 @@ fn boolean() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("return_true")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("return_true").call().unwrap();
assert_eq!(returns, BorshToken::Bool(true));
- let returns = vm
- .function("return_false")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("return_false").call().unwrap();
assert_eq!(returns, BorshToken::Bool(false));
vm.function("true_arg")
.arguments(&[BorshToken::Bool(true)])
- .accounts(vec![("dataAccount", data_account)])
.call();
vm.function("false_arg")
.arguments(&[BorshToken::Bool(false)])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -142,11 +131,7 @@ fn address() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("return_address")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("return_address").call().unwrap();
assert_eq!(
returns,
@@ -161,7 +146,6 @@ fn address() {
75, 161, 209, 89, 47, 84, 50, 13, 23, 127, 94, 21, 50, 249, 250, 185, 117, 49, 186,
134, 82, 130, 112, 97, 218, 24, 157, 198, 40, 105, 118, 27,
])])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -191,11 +175,7 @@ fn test_enum() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("return_enum")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("return_enum").call().unwrap();
assert_eq!(
returns,
@@ -210,7 +190,6 @@ fn test_enum() {
width: 8,
value: BigInt::from(6u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
@@ -259,11 +238,7 @@ fn bytes() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("return_literal")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("return_literal").call().unwrap();
assert_eq!(
returns,
@@ -273,7 +248,6 @@ fn bytes() {
let returns = vm
.function("return_arg")
.arguments(&[BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7])])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -298,7 +272,6 @@ fn bytes() {
BorshToken::FixedBytes(a.to_vec()),
BorshToken::FixedBytes(b.to_vec()),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -319,7 +292,6 @@ fn bytes() {
BorshToken::FixedBytes(a.to_vec()),
BorshToken::FixedBytes(b.to_vec()),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -333,7 +305,6 @@ fn bytes() {
BorshToken::FixedBytes(a.to_vec()),
BorshToken::FixedBytes(b.to_vec()),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -354,7 +325,6 @@ fn bytes() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -379,7 +349,6 @@ fn bytes() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -487,7 +456,6 @@ fn uint() {
width,
value: a.to_bigint().unwrap(),
}])
- .accounts(vec![("dataAccount", data_account)])
.call();
println!("{a:x} = {res:?} o");
@@ -504,7 +472,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -533,7 +500,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -560,7 +526,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -589,7 +554,6 @@ fn uint() {
value: BigInt::from(n),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -619,7 +583,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -647,7 +610,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -676,7 +638,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -703,7 +664,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -730,7 +690,6 @@ fn uint() {
value: b.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -759,7 +718,6 @@ fn uint() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -787,7 +745,6 @@ fn uint() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -850,7 +807,6 @@ fn test_power_overflow_boundaries() {
value: BigInt::from(width - 1),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -876,7 +832,6 @@ fn test_power_overflow_boundaries() {
value: BigInt::from(width + 1),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_ne!(sesa.unwrap(), 0);
@@ -923,7 +878,6 @@ fn test_overflow_boundaries() {
value: second_op.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
assert_eq!(
@@ -946,7 +900,6 @@ fn test_overflow_boundaries() {
value: second_op.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
assert_eq!(
@@ -980,7 +933,6 @@ fn test_overflow_boundaries() {
value: BigInt::from(2u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
contract
@@ -995,7 +947,6 @@ fn test_overflow_boundaries() {
value: BigInt::from(2),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
contract
@@ -1010,7 +961,6 @@ fn test_overflow_boundaries() {
value: upper_boundary.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
contract
@@ -1025,7 +975,6 @@ fn test_overflow_boundaries() {
value: lower_boundary.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
contract
@@ -1040,7 +989,6 @@ fn test_overflow_boundaries() {
value: lower_boundary.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
}
}
@@ -1089,7 +1037,6 @@ fn test_mul_within_range_signed() {
value: second_op.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1146,7 +1093,6 @@ fn test_mul_within_range() {
value: second_operand_rand.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
let res = first_operand_rand * second_operand_rand;
@@ -1208,7 +1154,6 @@ fn test_overflow_detect_signed() {
value: second_operand_rand.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
// The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1] .
@@ -1232,7 +1177,6 @@ fn test_overflow_detect_signed() {
value: second_operand_rand.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
// neg fails when value -(2^N)
@@ -1245,7 +1189,6 @@ fn test_overflow_detect_signed() {
width: width as u16,
value: lower_limit.clone(),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
lower_limit.add_assign(1usize);
@@ -1258,7 +1201,6 @@ fn test_overflow_detect_signed() {
width: width as u16,
value: first_operand_rand,
}])
- .accounts(vec![("dataAccount", data_account)])
.call();
}
}
@@ -1306,7 +1248,6 @@ fn test_overflow_detect_unsigned() {
value: second_operand_rand.to_bigint().unwrap(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
}
}
@@ -1394,7 +1335,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1421,7 +1361,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1448,7 +1387,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1476,7 +1414,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1503,7 +1440,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1531,7 +1467,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1558,7 +1493,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1585,7 +1519,6 @@ fn int() {
value: b.clone(),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1614,7 +1547,6 @@ fn int() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1642,7 +1574,6 @@ fn int() {
value: BigInt::from(r),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1695,7 +1626,6 @@ fn bytes_cast() {
let returns = vm
.function("to_bytes")
.arguments(&[BorshToken::FixedBytes(b"abcd".to_vec())])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1704,7 +1634,6 @@ fn bytes_cast() {
let returns = vm
.function("to_bytes5")
.arguments(&[BorshToken::Bytes(b"abcde".to_vec())])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -1762,3 +1691,34 @@ fn shift_after_load() {
}
);
}
+
+#[test]
+fn constant_program_id() {
+ let mut vm = build_solidity(
+ r#"
+ @program_id("5kQ3iJ43gHNDjqmSAtE1vDu18CiSAfNbRe4v5uoobh3U")
+contract hatchling {
+ constructor() {}
+
+ function getId() public view returns (address) {
+ return address(this);
+ }
+}
+ "#,
+ );
+
+ let data_account = vm.initialize_data_account();
+ vm.function("new")
+ .accounts(vec![("dataAccount", data_account)])
+ .call();
+
+ let res = vm.function("getId").call().unwrap();
+
+ let program_id: Account = "5kQ3iJ43gHNDjqmSAtE1vDu18CiSAfNbRe4v5uoobh3U"
+ .from_base58()
+ .unwrap()
+ .try_into()
+ .unwrap();
+
+ assert_eq!(res, BorshToken::Address(program_id));
+}
diff --git a/tests/solana_tests/rational.rs b/tests/solana_tests/rational.rs
index dfac7d253..e7cb605b4 100644
--- a/tests/solana_tests/rational.rs
+++ b/tests/solana_tests/rational.rs
@@ -26,11 +26,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -40,11 +36,7 @@ fn rational() {
}
);
- let returns = vm
- .function("test2")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test2").call().unwrap();
assert_eq!(
returns,
@@ -69,11 +61,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -98,11 +86,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -127,11 +111,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -156,11 +136,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -184,11 +160,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -212,11 +184,7 @@ fn rational() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(
returns,
@@ -246,7 +214,6 @@ fn rational() {
width: 64,
value: BigInt::from(982451653u32),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
diff --git a/tests/solana_tests/returns.rs b/tests/solana_tests/returns.rs
index c01669446..09c55255a 100644
--- a/tests/solana_tests/returns.rs
+++ b/tests/solana_tests/returns.rs
@@ -36,11 +36,7 @@ fn return_single() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("f").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -49,11 +45,7 @@ fn return_single() {
},
);
- let returns = vm
- .function("g")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("g").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -62,11 +54,7 @@ fn return_single() {
},
);
- let returns = vm
- .function("h")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("h").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -75,11 +63,7 @@ fn return_single() {
},
);
- let returns = vm
- .function("i")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("i").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -88,11 +72,7 @@ fn return_single() {
},
);
- let returns = vm
- .function("j")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("j").call().unwrap();
assert_eq!(
returns,
BorshToken::Uint {
@@ -117,12 +97,7 @@ fn return_ternary() {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap()
- .unwrap_tuple();
+ let returns = vm.function("f").call().unwrap().unwrap_tuple();
assert_eq!(
returns,
@@ -151,12 +126,7 @@ fn return_ternary() {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap()
- .unwrap_tuple();
+ let returns = vm.function("f").call().unwrap().unwrap_tuple();
assert_eq!(
returns,
@@ -286,12 +256,7 @@ fn return_function() {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap()
- .unwrap_tuple();
+ let returns = vm.function("f").call().unwrap().unwrap_tuple();
assert_eq!(
returns,
@@ -324,12 +289,7 @@ fn return_function() {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("f")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap()
- .unwrap_tuple();
+ let returns = vm.function("f").call().unwrap().unwrap_tuple();
assert_eq!(
returns,
diff --git a/tests/solana_tests/runtime_errors.rs b/tests/solana_tests/runtime_errors.rs
index d2be702fe..3e987a4d0 100644
--- a/tests/solana_tests/runtime_errors.rs
+++ b/tests/solana_tests/runtime_errors.rs
@@ -146,7 +146,6 @@ contract calle_contract {
width: 8,
value: BigInt::from(10u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
vm.logs,
@@ -160,7 +159,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(9u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -199,7 +197,6 @@ contract calle_contract {
width: 32,
value: BigInt::from(2u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -214,7 +211,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(u128::MAX),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -223,10 +219,7 @@ contract calle_contract {
);
vm.logs.clear();
- _res = vm
- .function("invalid_instruction")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
+ _res = vm.function("invalid_instruction").must_fail();
assert_eq!(
vm.logs,
@@ -253,7 +246,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(9u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -269,7 +261,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(9u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
println!("{}", vm.logs);
assert_eq!(
@@ -284,7 +275,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(19u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -300,7 +290,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(1u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -316,7 +305,6 @@ contract calle_contract {
width: 256,
value: BigInt::from(33u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.must_fail();
assert_eq!(
@@ -326,10 +314,7 @@ contract calle_contract {
vm.logs.clear();
- _res = vm
- .function("i_will_revert")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
+ _res = vm.function("i_will_revert").must_fail();
assert_eq!(
vm.logs,
diff --git a/tests/solana_tests/signature_verify.rs b/tests/solana_tests/signature_verify.rs
index 251268ae9..d4e206cbe 100644
--- a/tests/solana_tests/signature_verify.rs
+++ b/tests/solana_tests/signature_verify.rs
@@ -81,10 +81,7 @@ fn verify() {
BorshToken::Bytes(message.to_vec()),
BorshToken::Bytes(signature_bs.clone()),
])
- .accounts(vec![
- ("dataAccount", data_account),
- ("SysvarInstruction", instructions_account),
- ])
+ .accounts(vec![("SysvarInstruction", instructions_account)])
.call()
.unwrap();
@@ -116,10 +113,7 @@ fn verify() {
BorshToken::Bytes(message.to_vec()),
BorshToken::Bytes(signature_bs.clone()),
])
- .accounts(vec![
- ("dataAccount", data_account),
- ("SysvarInstruction", instructions_account),
- ])
+ .accounts(vec![("SysvarInstruction", instructions_account)])
.call()
.unwrap();
@@ -153,10 +147,7 @@ fn verify() {
BorshToken::Bytes(message.to_vec()),
BorshToken::Bytes(signature_bs),
])
- .accounts(vec![
- ("dataAccount", data_account),
- ("SysvarInstruction", instructions_account),
- ])
+ .accounts(vec![("SysvarInstruction", instructions_account)])
.call()
.unwrap();
diff --git a/tests/solana_tests/simple.rs b/tests/solana_tests/simple.rs
index c59da8ca4..f37525bdb 100644
--- a/tests/solana_tests/simple.rs
+++ b/tests/solana_tests/simple.rs
@@ -29,9 +29,7 @@ fn simple() {
vm.logs.truncate(0);
- vm.function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ vm.function("test").call();
assert_eq!(vm.logs, "Hello from function");
}
@@ -93,7 +91,6 @@ fn parameters() {
value: BigInt::from(10u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call();
assert_eq!(vm.logs, "x is 10");
@@ -111,7 +108,6 @@ fn parameters() {
value: BigInt::from(102u8),
},
])
- .accounts(vec![("dataAccount", data_account)])
.call();
assert_eq!(vm.logs, "y is 102");
@@ -139,7 +135,6 @@ fn returns() {
width: 32,
value: BigInt::from(10u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -171,7 +166,6 @@ fn returns() {
width: 64,
value: BigInt::from(982451653u64),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -484,7 +478,6 @@ contract test3 {
width: 32,
value: BigInt::from(i),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -509,7 +502,6 @@ contract test3 {
},
BorshToken::Bool(true),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -538,7 +530,6 @@ contract test3 {
},
BorshToken::Bool(false),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -568,7 +559,6 @@ contract test3 {
width: 32,
value: BigInt::from(i),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap();
@@ -601,11 +591,7 @@ fn overloading() {
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("foo_")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("foo_").call().unwrap();
assert_eq!(
returns,
@@ -615,11 +601,7 @@ fn overloading() {
}
);
- let returns = vm
- .function("foo_bar")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("foo_bar").call().unwrap();
assert_eq!(
returns,
@@ -631,7 +613,6 @@ fn overloading() {
let returns = vm
.function("foo_address")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::Address([0u8; 32])])
.call()
.unwrap();
@@ -646,7 +627,6 @@ fn overloading() {
let returns = vm
.function("foo_bytes32")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::FixedBytes(vec![0u8; 32])])
.call()
.unwrap();
@@ -660,7 +640,6 @@ fn overloading() {
);
let returns = vm
.function("foo_bytes")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::Bytes(vec![])])
.call()
.unwrap();
@@ -675,7 +654,6 @@ fn overloading() {
let returns = vm
.function("foo_string")
- .accounts(vec![("dataAccount", data_account)])
.arguments(&[BorshToken::String("yo".into())])
.call()
.unwrap();
diff --git a/tests/solana_tests/using.rs b/tests/solana_tests/using.rs
index 22a13cfe0..7cd651406 100644
--- a/tests/solana_tests/using.rs
+++ b/tests/solana_tests/using.rs
@@ -34,10 +34,7 @@ fn using_for_contracts() {
.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test").call();
assert_eq!(runtime.logs, "Hello");
@@ -84,10 +81,12 @@ fn using_for_contracts() {
.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
+
+ let program_id = runtime.stack[0].id;
runtime
.function("test")
.accounts(vec![
- ("dataAccount", data_account),
+ ("I_programId", program_id),
("systemProgram", [0; 32]),
])
.call();
@@ -225,16 +224,7 @@ fn user_defined_oper() {
.accounts(vec![("dataAccount", data_account)])
.call();
- runtime
- .function("test_cmp")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- runtime
- .function("test_arith")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- runtime
- .function("test_bit")
- .accounts(vec![("dataAccount", data_account)])
- .call();
+ runtime.function("test_cmp").call();
+ runtime.function("test_arith").call();
+ runtime.function("test_bit").call();
}
diff --git a/tests/solana_tests/vector_to_slice.rs b/tests/solana_tests/vector_to_slice.rs
index 3278e58f2..54245f7c0 100644
--- a/tests/solana_tests/vector_to_slice.rs
+++ b/tests/solana_tests/vector_to_slice.rs
@@ -24,11 +24,7 @@ fn test_slice_in_phi() {
vm.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = vm
- .function("test")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = vm.function("test").call().unwrap();
assert_eq!(returns, BorshToken::String(String::from("Hello!")));
}
diff --git a/tests/solana_tests/yul.rs b/tests/solana_tests/yul.rs
index 2428737f3..68eac1260 100644
--- a/tests/solana_tests/yul.rs
+++ b/tests/solana_tests/yul.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
-use crate::{build_solidity, BorshToken};
+use crate::{build_solidity, AccountMeta, BorshToken, Pubkey};
use num_bigint::{BigInt, Sign};
use num_traits::{One, Zero};
@@ -32,7 +32,7 @@ contract testing {
return ret;
}
- function call_data_array(uint32[] calldata vl) public pure returns (uint256, uint256) {
+ function call_data_array(uint32[] calldata vl) public view returns (uint256, uint256) {
uint256 ret1 = 98;
uint256 ret2 = 99;
assembly {
@@ -120,17 +120,17 @@ contract testing {
let returns = vm
.function("selector_address")
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
+ let program_id = vm.stack[0].id;
assert_eq!(
returns,
vec![
BorshToken::Uint {
width: 256,
- value: BigInt::from_bytes_be(Sign::Plus, data_account.as_ref())
+ value: BigInt::from_bytes_be(Sign::Plus, program_id.as_ref())
},
BorshToken::Uint {
width: 256,
@@ -191,7 +191,6 @@ contract testing {
width: 64,
value: BigInt::from(5u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -216,7 +215,6 @@ contract testing {
width: 64,
value: BigInt::from(78u8),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -241,7 +239,6 @@ contract testing {
width: 64,
value: BigInt::from(259u16),
}])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -488,7 +485,6 @@ fn external_function() {
},
BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7, 8]),
])
- .accounts(vec![("dataAccount", data_account)])
.call()
.unwrap()
.unwrap_tuple();
@@ -528,16 +524,13 @@ contract testing {
);
let data_account = runtime.initialize_data_account();
+ let program_id = runtime.stack[0].id;
runtime
.function("new")
.accounts(vec![("dataAccount", data_account)])
.call();
- let returns = runtime
- .function("test_address")
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
+ let returns = runtime.function("test_address").call().unwrap();
let addr = returns.into_bigint().unwrap();
let mut b_vec = addr.to_bytes_be().1;
// test_address() returns address as uint256. If the highest bits are 0, then addr.to_bytes_be().1
@@ -545,16 +538,16 @@ contract testing {
while b_vec.len() < 32 {
b_vec.insert(0, 0);
}
- assert_eq!(&b_vec, data_account.as_ref());
+ assert_eq!(&b_vec, program_id.as_ref());
- runtime
- .account_data
- .get_mut(&data_account)
- .unwrap()
- .lamports = 102;
+ runtime.account_data.get_mut(&program_id).unwrap().lamports = 102;
let returns = runtime
.function("test_balance")
- .accounts(vec![("dataAccount", data_account)])
+ .remaining_accounts(&[AccountMeta {
+ pubkey: Pubkey(program_id),
+ is_writable: false,
+ is_signer: false,
+ }])
.call()
.unwrap();
assert_eq!(
@@ -567,7 +560,11 @@ contract testing {
let returns = runtime
.function("test_selfbalance")
- .accounts(vec![("dataAccount", data_account)])
+ .remaining_accounts(&[AccountMeta {
+ pubkey: Pubkey(program_id),
+ is_signer: false,
+ is_writable: false,
+ }])
.call()
.unwrap();