| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- // SPDX-License-Identifier: Apache-2.0
- use crate::{
- build_solidity, create_program_address, AccountMeta, AccountState, BorshToken, Instruction,
- Pubkey, VirtualMachine,
- };
- use base58::FromBase58;
- use num_bigint::BigInt;
- use num_traits::One;
- #[test]
- fn simple_external_call() {
- let mut vm = build_solidity(
- r#"
- contract bar0 {
- function test_bar(string v) public {
- print("bar0 says: " + v);
- }
- function test_other(address x) public {
- bar1.test_bar{program_id: x}("cross contract call");
- }
- }
- contract bar1 {
- function test_bar(string v) public {
- print("bar1 says: " + v);
- }
- }"#,
- );
- let bar1_account = vm.initialize_data_account();
- let bar1_program_id = vm.stack[0].id;
- vm.function("new")
- .accounts(vec![("dataAccount", bar1_account)])
- .call();
- vm.function("test_bar")
- .arguments(&[BorshToken::String(String::from("yo"))])
- .call();
- assert_eq!(vm.logs, "bar1 says: yo");
- vm.logs.truncate(0);
- vm.set_program(0);
- let bar0_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", bar0_account)])
- .call();
- vm.function("test_bar")
- .arguments(&[BorshToken::String(String::from("uncle beau"))])
- .call();
- assert_eq!(vm.logs, "bar0 says: uncle beau");
- vm.logs.truncate(0);
- vm.function("test_other")
- .accounts(vec![
- ("bar1_programId", bar1_program_id),
- ("systemProgram", [0; 32]),
- ])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .call();
- assert_eq!(vm.logs, "bar1 says: cross contract call");
- }
- #[test]
- fn external_call_with_returns() {
- let mut vm = build_solidity(
- r#"
- contract bar0 {
- function test_other(address x) public returns (int64) {
- return bar1.test_bar{program_id: x}(7) + 5;
- }
- }
- contract bar1 {
- function test_bar(int64 y) public returns (int64) {
- return 3 + y;
- }
- }"#,
- );
- let bar1_account = vm.initialize_data_account();
- let bar1_program_id = vm.stack[0].id;
- vm.function("new")
- .accounts(vec![("dataAccount", bar1_account)])
- .call();
- let res = vm
- .function("test_bar")
- .arguments(&[BorshToken::Int {
- width: 64,
- value: BigInt::from(21),
- }])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(24u8)
- }
- );
- vm.set_program(0);
- let bar0_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", bar0_account)])
- .call();
- let res = vm
- .function("test_other")
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .accounts(vec![
- ("bar1_programId", bar1_program_id),
- ("systemProgram", [0; 32]),
- ])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(15u8)
- }
- );
- }
- #[test]
- fn external_raw_call_with_returns() {
- let mut vm = build_solidity(
- r#"
- contract bar0 {
- bytes8 private constant SELECTOR = bytes8(sha256(bytes('global:test_bar')));
- function test_other(address x) public returns (int64) {
- bytes select = abi.encodeWithSelector(SELECTOR, int64(7));
- bytes signature = abi.encodeWithSignature("global:test_bar", int64(7));
- require(select == signature, "must be the same");
- (, bytes raw) = address(x).call(signature);
- (int64 v) = abi.decode(raw, (int64));
- return v + 5;
- }
- }
- contract bar1 {
- function test_bar(int64 y) public returns (int64) {
- return 3 + y;
- }
- }"#,
- );
- let bar1_account = vm.initialize_data_account();
- let bar1_program_id = vm.stack[0].id;
- vm.function("new")
- .accounts(vec![("dataAccount", bar1_account)])
- .call();
- let res = vm
- .function("test_bar")
- .arguments(&[BorshToken::Int {
- width: 64,
- value: BigInt::from(21u8),
- }])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(24u8),
- }
- );
- vm.set_program(0);
- let bar0_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", bar0_account)])
- .call();
- let res = vm
- .function("test_other")
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .accounts(vec![("systemProgram", [0; 32])])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(15u8),
- }
- );
- }
- #[test]
- fn call_external_func_type() {
- let mut vm = build_solidity(
- r#"
- contract testing {
- function testPtr(int a) public pure returns (int, int) {
- return (a/2, 3);
- }
- function doTest() public view returns (int, int) {
- function(int) external pure returns (int, int) sfPtr = this.testPtr;
- (int a, int b) = sfPtr(2);
- return (a, b);
- }
- }
- "#,
- );
- let data_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- let res = vm
- .function("doTest")
- .accounts(vec![("systemProgram", [0; 32])])
- .call()
- .unwrap()
- .unwrap_tuple();
- assert_eq!(
- res,
- vec![
- BorshToken::Int {
- width: 256,
- value: BigInt::one(),
- },
- BorshToken::Int {
- width: 256,
- value: BigInt::from(3u8)
- }
- ]
- );
- }
- #[test]
- fn external_call_with_string_returns() {
- let mut vm = build_solidity(
- r#"
- contract bar0 {
- function test_other(address x) public returns (string) {
- string y = bar1.test_bar{program_id: x}(7);
- print(y);
- return y;
- }
- function test_this(address x) public {
- address a = bar1.who_am_i{program_id: x}();
- assert(a == address(x));
- }
- }
- contract bar1 {
- function test_bar(int64 y) public returns (string) {
- return "foo:{}".format(y);
- }
- function who_am_i() public returns (address) {
- return address(this);
- }
- }"#,
- );
- let bar1_account = vm.initialize_data_account();
- let bar1_program_id = vm.stack[0].id;
- vm.function("new")
- .accounts(vec![("dataAccount", bar1_account)])
- .call();
- let res = vm
- .function("test_bar")
- .arguments(&[BorshToken::Int {
- width: 64,
- value: BigInt::from(22u8),
- }])
- .call()
- .unwrap();
- assert_eq!(res, BorshToken::String(String::from("foo:22")));
- vm.set_program(0);
- let bar0_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", bar0_account)])
- .call();
- let res = vm
- .function("test_other")
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .accounts(vec![
- ("bar1_programId", bar1_program_id),
- ("systemProgram", [0; 32]),
- ])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .call()
- .unwrap();
- assert_eq!(res, BorshToken::String(String::from("foo:7")));
- vm.function("test_this")
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .accounts(vec![
- ("bar1_programId", bar1_program_id),
- ("systemProgram", [0; 32]),
- ])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .call();
- }
- #[test]
- fn encode_call() {
- let mut vm = build_solidity(
- r#"
- contract bar0 {
- bytes8 private constant SELECTOR = bytes8(sha256(bytes('global:test_bar')));
- function test_other(address x) public returns (int64) {
- bytes select = abi.encodeWithSelector(SELECTOR, int64(7));
- bytes signature = abi.encodeCall(bar1.test_bar, 7);
- require(select == signature, "must be the same");
- (, bytes raw) = address(x).call(signature);
- (int64 v) = abi.decode(raw, (int64));
- return v + 5;
- }
- }
- contract bar1 {
- function test_bar(int64 y) public pure returns (int64) {
- return 3 + y;
- }
- }"#,
- );
- let bar1_account = vm.initialize_data_account();
- let bar1_program_id = vm.stack[0].id;
- vm.function("new")
- .accounts(vec![("dataAccount", bar1_account)])
- .call();
- let res = vm
- .function("test_bar")
- .arguments(&[BorshToken::Int {
- width: 64,
- value: BigInt::from(21u8),
- }])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(24u8)
- }
- );
- vm.set_program(0);
- let bar0_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", bar0_account)])
- .call();
- let res = vm
- .function("test_other")
- .arguments(&[BorshToken::Address(bar1_program_id)])
- .accounts(vec![("systemProgram", [0; 32])])
- .remaining_accounts(&[
- AccountMeta {
- pubkey: Pubkey(bar1_account),
- is_writable: false,
- is_signer: false,
- },
- AccountMeta {
- pubkey: Pubkey(bar1_program_id),
- is_signer: false,
- is_writable: false,
- },
- ])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 64,
- value: BigInt::from(15u8)
- }
- );
- }
- #[test]
- fn internal_function_storage() {
- let mut vm = build_solidity(
- r#"
- contract ft {
- function(int32,int32) internal returns (int32) func;
- function mul(int32 a, int32 b) internal returns (int32) {
- return a * b;
- }
- function add(int32 a, int32 b) internal returns (int32) {
- return a + b;
- }
- function set_op(bool action) public {
- if (action) {
- func = mul;
- } else {
- func = add;
- }
- }
- function test(int32 a, int32 b) public returns (int32) {
- return func(a, b);
- }
- }"#,
- );
- let data_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- let res = vm
- .function("set_op")
- .arguments(&[BorshToken::Bool(true)])
- .accounts(vec![("dataAccount", data_account)])
- .call();
- assert!(res.is_none());
- let res = vm
- .function("test")
- .arguments(&[
- BorshToken::Int {
- width: 32,
- value: BigInt::from(3u8),
- },
- BorshToken::Int {
- width: 32,
- value: BigInt::from(5u8),
- },
- ])
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 32,
- value: BigInt::from(15u8)
- }
- );
- let res = vm
- .function("set_op")
- .arguments(&[BorshToken::Bool(false)])
- .accounts(vec![("dataAccount", data_account)])
- .call();
- assert!(res.is_none());
- let res = vm
- .function("test")
- .arguments(&[
- BorshToken::Int {
- width: 32,
- value: BigInt::from(3u8),
- },
- BorshToken::Int {
- width: 32,
- value: BigInt::from(5u8),
- },
- ])
- .accounts(vec![("dataAccount", data_account)])
- .call()
- .unwrap();
- assert_eq!(
- res,
- BorshToken::Int {
- width: 32,
- value: BigInt::from(8u8)
- }
- );
- }
- #[test]
- fn raw_call_accounts() {
- let mut vm = build_solidity(
- r#"
- import {AccountMeta} from 'solana';
- contract SplToken {
- address constant tokenProgramId = address"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
- address constant SYSVAR_RENT_PUBKEY = address"SysvarRent111111111111111111111111111111111";
- struct InitializeMintInstruction {
- uint8 instruction;
- uint8 decimals;
- address mintAuthority;
- uint8 freezeAuthorityOption;
- address freezeAuthority;
- }
- function create_mint_with_freezeauthority(uint8 decimals, address mintAuthority, address freezeAuthority) public {
- InitializeMintInstruction instr = InitializeMintInstruction({
- instruction: 0,
- decimals: decimals,
- mintAuthority: mintAuthority,
- freezeAuthorityOption: 1,
- freezeAuthority: freezeAuthority
- });
- AccountMeta[2] metas = [
- AccountMeta({pubkey: instr.mintAuthority, is_writable: true, is_signer: false}),
- AccountMeta({pubkey: SYSVAR_RENT_PUBKEY, is_writable: false, is_signer: false})
- ];
- tokenProgramId.call{accounts: metas}(instr);
- }
- }"#,
- );
- let data_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- let token = Pubkey(
- "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
- .from_base58()
- .unwrap()
- .try_into()
- .unwrap(),
- );
- vm.account_data.insert(token.0, AccountState::default());
- let test_args = |_vm: &VirtualMachine, instr: &Instruction, _signers: &[Pubkey]| {
- let sysvar_rent = Pubkey(
- "SysvarRent111111111111111111111111111111111"
- .from_base58()
- .unwrap()
- .try_into()
- .unwrap(),
- );
- assert_eq!(
- &instr.data,
- &[
- 0, 11, 113, 117, 105, 110, 113, 117, 97, 103, 105, 110, 116, 97, 113, 117, 97, 100,
- 114, 105, 110, 103, 101, 110, 116, 105, 108, 108, 105, 97, 114, 100, 116, 104, 1,
- 113, 117, 105, 110, 113, 117, 97, 103, 105, 110, 116, 97, 113, 117, 97, 100, 114,
- 105, 110, 103, 101, 110, 116, 105, 108, 108, 105, 111, 110, 116, 104, 115,
- ]
- );
- assert!(instr.accounts[0].is_writable);
- assert!(!instr.accounts[0].is_signer);
- assert_eq!(
- instr.accounts[0].pubkey,
- Pubkey([
- 113, 117, 105, 110, 113, 117, 97, 103, 105, 110, 116, 97, 113, 117, 97, 100, 114,
- 105, 110, 103, 101, 110, 116, 105, 108, 108, 105, 97, 114, 100, 116, 104
- ])
- );
- assert!(!instr.accounts[1].is_writable);
- assert!(!instr.accounts[1].is_signer);
- assert_eq!(instr.accounts[1].pubkey, sysvar_rent);
- };
- vm.call_params_check.insert(token.clone(), test_args);
- vm.function("create_mint_with_freezeauthority")
- .arguments(&[
- BorshToken::Uint {
- width: 8,
- value: BigInt::from(11u8),
- },
- BorshToken::Address(b"quinquagintaquadringentilliardth".to_owned()),
- BorshToken::Address(b"quinquagintaquadringentillionths".to_owned()),
- ])
- .accounts(vec![("tokenProgram", token.0), ("systemProgram", [0; 32])])
- .call();
- }
- #[test]
- fn pda() {
- let mut vm = build_solidity(
- r#"
- import {AccountMeta} from 'solana';
- contract pda {
- address constant tokenProgramId = address"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
- address constant SYSVAR_RENT_PUBKEY = address"SysvarRent111111111111111111111111111111111";
- function test() public {
- bytes instr = new bytes(1);
- AccountMeta[1] metas = [
- AccountMeta({pubkey: SYSVAR_RENT_PUBKEY, is_writable: false, is_signer: false})
- ];
- bytes3 foo = "foo";
- address addr = address"8dtukUTHTZoVQTA5i4UdC2z6A2b5yvnJhkzhYnwAk3Fm";
- tokenProgramId.call{seeds: [ [ foo ] , ["b", "a", "r"], [addr], [foo, addr, "meh"] ], accounts: metas}(instr);
- }
- }"#,
- );
- let data_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- let test_args = |vm: &VirtualMachine, _instr: &Instruction, signers: &[Pubkey]| {
- assert_eq!(
- signers[0],
- create_program_address(&vm.stack[0].id, &[b"foo"])
- );
- assert_eq!(
- signers[1],
- create_program_address(&vm.stack[0].id, &[b"bar"])
- );
- assert_eq!(
- signers[2],
- create_program_address(&vm.stack[0].id, &[b"quinquagintaquadringentilliardth"])
- );
- assert_eq!(
- signers[3],
- create_program_address(
- &vm.stack[0].id,
- &[b"fooquinquagintaquadringentilliardthmeh"]
- )
- );
- };
- let token = Pubkey(
- "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
- .from_base58()
- .unwrap()
- .try_into()
- .unwrap(),
- );
- vm.account_data.insert(token.0, AccountState::default());
- vm.call_params_check.insert(token.clone(), test_args);
- vm.function("test")
- .accounts(vec![("tokenProgram", token.0), ("systemProgram", [0; 32])])
- .call();
- }
|