diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a7d2c4..eb5d8c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.10.0 (18.05.2023) + +- [Soroban.ex improvements](https://github.com/kommitters/soroban.ex/issues/84) + ## 0.9.0 (18.05.2023) - [Retrieve unsigned transactions](https://github.com/kommitters/soroban.ex/issues/70) diff --git a/README.md b/README.md index 7dbd302..19985ae 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ ```elixir def deps do [ - {:soroban, "~> 0.9.0"} + {:soroban, "~> 0.10.0"} ] end ``` @@ -466,6 +466,14 @@ The deployment and invocation of Soroban smart contracts is done through the `So #### Invoke contract function +**Parameters** + +- `contract_id`: Identifier of the contract to be invoked. +- `source_secret_key`: Secret key of the function invoker responsible for signing the transaction. +- `function_name`: String indicating the name of the function to be invoked. +- `function_args`: List of `Soroban.Types` representing the arguments required by the indicated function (`function_name`). They should be provided in the specific order expected by the function. +- `auth_secret_key`: (optional) Secret key used to authorize the function invocation when the function invoker is not the same function authorizer. + ##### Simple invocation - no authorization required ```elixir @@ -492,7 +500,7 @@ Contract.invoke(contract_id, source_secret_key, function_name, function_args) ##### Invocation with required authorization -- When the invoker is the signer +- When the function invoker authorizes the function invocation ```elixir alias Soroban.Contract @@ -519,7 +527,7 @@ Contract.invoke(contract_id, source_secret_key, function_name, function_args) }} ``` -- When the invoker is not the signer +- When the function invoker is not the function authorizer. ```elixir alias Soroban.Contract @@ -535,9 +543,9 @@ Contract.invoke(contract_id, source_secret_key, function_name, function_args) Int128.new(4500) ] - auth_accounts = ["SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK"] + auth_secret_key = "SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK" - Contract.invoke(contract_id, source_secret_key, function_name, function_args, auth_accounts) + Contract.invoke(contract_id, source_secret_key, function_name, function_args, auth_secret_key) {:ok, %Soroban.RPC.SendTransactionResponse{ @@ -553,6 +561,11 @@ Contract.invoke(contract_id, source_secret_key, function_name, function_args) ##### Install Contract Code +**Parameters** + +- `wasm`: Binary of the web assembly (WASM) file resulting from building the contract. +- `secret_key`: Secret key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract alias Soroban.RPC.SendTransactionResponse @@ -582,6 +595,11 @@ wasm_id = ##### Deploy Contract from WASM +**Parameters** + +- `wasm_id`: Binary identification of the installed contract to deploy. +- `secret_key`: Secret key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract alias Soroban.RPC.SendTransactionResponse @@ -610,6 +628,11 @@ hash ##### Deploy Asset Contract +**Parameters** + +- `asset_code`: String from 1 to 12 characters indicating the asset symbol. +- `secret_key`: Secret key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract alias Soroban.RPC.SendTransactionResponse @@ -644,6 +667,13 @@ This XDR is required by wallets to sign transactions before they can be submitte #### Invoke contract function +**Parameters** + +- `contract_id`: Identifier of the contract to be invoked. +- `source_public_key`: Public key of the function invoker responsible for signing the transaction. +- `function_name`: String value indicating the name of the function to be invoked. +- `function_args`: List of `Soroban.Types` representing the arguments required by the indicated function (`function_name`). They should be provided in the specific order expected by the function. + ```elixir alias Soroban.Contract alias Soroban.Types.Symbol @@ -667,6 +697,11 @@ Contract.retrieve_unsigned_xdr_to_invoke( #### Install contract code +**Parameters** + +- `wasm`: Binary of the web assembly (WASM) file resulting from building the contract. +- `source_public_key`: Public key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract @@ -681,6 +716,11 @@ Contract.retrieve_unsigned_xdr_to_install(wasm, source_public_key) #### Deploy Contract +**Parameters** + +- `wasm_id`: Binary identification of the installed contract to deploy. +- `source_public_key`: Public key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract @@ -696,6 +736,11 @@ Contract.retrieve_unsigned_xdr_to_deploy(wasm_id, source_public_key) #### Deploy Asset Contract +**Parameters** + +- `asset_code`: String from 1 to 12 characters indicating the asset symbol. +- `source_public_key`: Public key of the function invoker responsible for signing the transaction. + ```elixir alias Soroban.Contract diff --git a/lib/contract.ex b/lib/contract.ex index 4de5ae0..835eaa4 100644 --- a/lib/contract.ex +++ b/lib/contract.ex @@ -15,7 +15,7 @@ defmodule Soroban.Contract do source_secret_key, function_name, function_args \\ [], - auth_accounts \\ [] + auth_secret_key \\ nil ), to: InvokeContractFunction, as: :invoke diff --git a/lib/contract/invoke_contract_function.ex b/lib/contract/invoke_contract_function.ex index b189ece..e35a0df 100644 --- a/lib/contract/invoke_contract_function.ex +++ b/lib/contract/invoke_contract_function.ex @@ -19,7 +19,7 @@ defmodule Soroban.Contract.InvokeContractFunction do @type account :: Account.t() @type function_args :: list(struct()) - @type auth_accounts :: list(binary()) + @type auth_secret_key :: binary() | nil @type invoke_host_function :: InvokeHostFunction.t() @type envelope_xdr :: String.t() @type function_name :: String.t() @@ -36,14 +36,14 @@ defmodule Soroban.Contract.InvokeContractFunction do source_secret_key :: source_secret_key(), function_name :: function_name(), function_args :: function_args(), - auth_accounts :: auth_accounts() + auth_secret_key :: auth_secret_key() ) :: send_response() def invoke( contract_id, source_secret_key, function_name, function_args, - auth_accounts \\ [] + auth_secret_key \\ nil ) do with {public_key, _secret} = keypair <- Stellar.KeyPair.from_secret_seed(source_secret_key), {:ok, seq_num} <- Accounts.fetch_next_sequence_number(public_key), @@ -52,8 +52,7 @@ defmodule Soroban.Contract.InvokeContractFunction do %Account{} = source_account <- Account.new(public_key), %SequenceNumber{} = sequence_number <- SequenceNumber.new(seq_num), %InvokeHostFunction{} = invoke_host_function_op <- - create_host_function_op(contract_id, function_name, function_args), - auth_account <- Enum.at(auth_accounts, 0) do + create_host_function_op(contract_id, function_name, function_args) do invoke_host_function_op |> RPCCalls.simulate(source_account, sequence_number) |> RPCCalls.send_transaction( @@ -61,7 +60,7 @@ defmodule Soroban.Contract.InvokeContractFunction do sequence_number, signature, invoke_host_function_op, - auth_account + auth_secret_key ) end end diff --git a/lib/contract/rpc_calls.ex b/lib/contract/rpc_calls.ex index b0b81ff..7a14ab6 100644 --- a/lib/contract/rpc_calls.ex +++ b/lib/contract/rpc_calls.ex @@ -17,7 +17,7 @@ defmodule Soroban.Contract.RPCCalls do @type account :: Account.t() @type auth :: String.t() | nil - @type auth_account :: String.t() | nil + @type auth_secret_key :: String.t() | nil @type envelope_xdr :: String.t() @type invoke_host_function :: InvokeHostFunction.t() @type simulate_response :: {:ok, SimulateTransactionResponse.t()} @@ -57,7 +57,7 @@ defmodule Soroban.Contract.RPCCalls do _sequence_number, _signature, _invoke_host_function_op, - auth_account \\ nil + auth_secret_key \\ nil ) def send_transaction( @@ -66,10 +66,10 @@ defmodule Soroban.Contract.RPCCalls do sequence_number, signature, invoke_host_function_op, - auth_account + auth_secret_key ) do invoke_host_function_op = - set_invoke_host_function_params(invoke_host_function_op, footprint, auth, auth_account) + set_invoke_host_function_params(invoke_host_function_op, footprint, auth, auth_secret_key) {:ok, envelope_xdr} = source_account @@ -87,7 +87,7 @@ defmodule Soroban.Contract.RPCCalls do _sequence_number, _signature, _invoke_host_function_op, - _auth_account + _auth_secret_key ), do: response @@ -127,7 +127,7 @@ defmodule Soroban.Contract.RPCCalls do invoke_host_function :: invoke_host_function(), footprint :: String.t(), auth :: auth(), - auth_account :: auth_account() + auth_secret_key :: auth_secret_key() ) :: invoke_host_function() | {:error, :required_auth} defp set_invoke_host_function_params(invoke_host_function_op, footprint, [auth], nil) do invoke_host_function_op @@ -135,14 +135,19 @@ defmodule Soroban.Contract.RPCCalls do |> InvokeHostFunction.set_contract_auth(auth) end - defp set_invoke_host_function_params(invoke_host_function_op, footprint, [auth], auth_account) do - authorization = ContractAuth.sign_xdr(auth, auth_account) + defp set_invoke_host_function_params( + invoke_host_function_op, + footprint, + [auth], + auth_secret_key + ) do + authorization = ContractAuth.sign_xdr(auth, auth_secret_key) invoke_host_function_op |> InvokeHostFunction.set_footprint(footprint) |> InvokeHostFunction.set_contract_auth(authorization) end - defp set_invoke_host_function_params(invoke_host_function_op, footprint, nil, _auth_account), + defp set_invoke_host_function_params(invoke_host_function_op, footprint, nil, _auth_secret_key), do: InvokeHostFunction.set_footprint(invoke_host_function_op, footprint) end diff --git a/mix.exs b/mix.exs index a1ccf91..ba6c221 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Soroban.MixProject do use Mix.Project - @version "0.9.0" + @version "0.10.0" @github_url "https://github.com/kommitters/soroban.ex" def project do diff --git a/test/contract/invoke_contract_function_test.exs b/test/contract/invoke_contract_function_test.exs index 17116a9..fe6cfa5 100644 --- a/test/contract/invoke_contract_function_test.exs +++ b/test/contract/invoke_contract_function_test.exs @@ -205,7 +205,7 @@ defmodule Soroban.Contract.InvokeContractFunctionTest do source_secret_with_error: "SDXKY6TSBNS7T2UJMHLIH4BWTP4EHR52HZTRNEKH33ML3ARJI2AKIPEC", function_name: "function_name", function_args: [Symbol.new("Arg")], - auth_accounts: ["SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK"], + auth_secret_key: "SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK", xdr_envelope: "AAAAAgAAAADJTnjlYcJxSKDat78jbEyDkVqo2uhpNX4BdBtqGrx+1gAAAGQABPEIAAAAPgAAAAAAAAAAAAAAAQAAAAAAAAAYAAAAAAAAAAMAAAANAAAAIL5BOLMcxdDZ2RtTGT10MW0lRAZ5TsD4HT7UD03BuGpuAAAADwAAAA1mdW5jdGlvbl9uYW1lAAAAAAAADwAAAANBcmcAAAAAAgAAAAbRT4ReAkUa6lMq9OExKvhlyTk7tBFtSkBT/PaIo3WjUgAAABQAAAAHQtAjKFI/GD4AoVvILmUtGNiMgqn+2QuDLQmXBcK8zRoAAAAAAAAAAAAAAAAAAAAA" } @@ -238,7 +238,7 @@ defmodule Soroban.Contract.InvokeContractFunctionTest do source_secret_with_auth: source_secret_with_auth, function_name: function_name, function_args: function_args, - auth_accounts: auth_accounts + auth_secret_key: auth_secret_key } do {:ok, %SendTransactionResponse{ @@ -253,7 +253,7 @@ defmodule Soroban.Contract.InvokeContractFunctionTest do source_secret_with_auth, function_name, function_args, - auth_accounts + auth_secret_key ) end diff --git a/test/contract_test.exs b/test/contract_test.exs index 5081b9e..e334d41 100644 --- a/test/contract_test.exs +++ b/test/contract_test.exs @@ -88,7 +88,7 @@ defmodule Soroban.ContractTest do # GDDZSR7Y6TIMSBM72WYVGUH6FB6P7MF6Y6DU7MCNAPFRXI5GCWGWWFRS function_name: "function_name", function_args: [Symbol.new("Arg")], - auth_accounts: ["SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK"], + auth_secret_key: "SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK", asset_code: :ZZZ, wasm: <<0, 97, 115, 109, 1, 0, 0, 0, 1, 65, 12, 96, 1, 126, 1, 126, 96, 2, 126, 126, 1, 126, 96, @@ -152,6 +152,30 @@ defmodule Soroban.ContractTest do ) end + test "invoke/5 with args and auth_secret_key", %{ + auth_secret_key: auth_secret_key, + contract_id: contract_id, + source_secret: source_secret, + function_name: function_name, + function_args: function_args + } do + {:ok, + %SendTransactionResponse{ + status: "PENDING", + hash: "a4721e2a61e9a6b3f54030396e41c3e352101e6cd649b4453e89fb3e827744f4", + latest_ledger: "476420", + latest_ledger_close_time: "1683150612", + error_result_xdr: nil + }} = + Contract.invoke( + contract_id, + source_secret, + function_name, + function_args, + auth_secret_key + ) + end + test "install/2", %{ wasm: wasm, source_secret: source_secret