diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index db6d470b..816d58d3 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -20,7 +20,7 @@ jobs: HEX_API_KEY: ${{ secrets.HEX_API_KEY }} steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604 # v2.5.0 with: disable-sudo: true egress-policy: block @@ -30,8 +30,8 @@ jobs: repo.hex.pm:443 builds.hex.pm:443 - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - - uses: erlef/setup-elixir@c2e02f777c158310fc6d3d4e11b36a52d2d52db8 # v1.15.4 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: erlef/setup-elixir@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0 with: otp-version: ${{ matrix.otp }} elixir-version: ${{ matrix.elixir }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 928299a5..5513e777 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: MIX_ENV: test steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604 # v2.5.0 with: disable-sudo: true egress-policy: block @@ -32,8 +32,8 @@ jobs: repo.hex.pm:443 builds.hex.pm:443 - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - - uses: erlef/setup-elixir@c2e02f777c158310fc6d3d4e11b36a52d2d52db8 # v1.15.4 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: erlef/setup-elixir@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0 with: otp-version: ${{ matrix.otp }} elixir-version: ${{ matrix.elixir }} @@ -63,7 +63,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604 # v2.5.0 with: disable-sudo: true egress-policy: block diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index dac9326b..dfc21ce0 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604 # v2.5.0 with: disable-sudo: true egress-policy: block @@ -37,12 +37,12 @@ jobs: sigstore-tuf-root.storage.googleapis.com:443 - name: "Checkout code" - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af # v2.1.3 + uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0 with: results_file: results.sarif results_format: sarif @@ -69,6 +69,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2.21.0 with: sarif_file: results.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index 2440337e..b9189676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.16.0 (25.07.2023) + +* Add support for contract function invocation with Soroban Preview 10. +* Update all dependencies. + ## 0.15.1 (13.06.2023) * Fix `SCAddress` contract type. diff --git a/README.md b/README.md index ec8e7e25..c07c1c4c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The **Stellar SDK** is composed of two complementary components: **`TxBuild`** + ```elixir def deps do [ - {:stellar_sdk, "~> 0.15.1"} + {:stellar_sdk, "~> 0.16.0"} ] end ``` diff --git a/docs/examples/soroban/invoke_contract_functions.md b/docs/examples/soroban/invoke_contract_functions.md index 729de13d..5c02ce9f 100644 --- a/docs/examples/soroban/invoke_contract_functions.md +++ b/docs/examples/soroban/invoke_contract_functions.md @@ -15,8 +15,8 @@ alias Stellar.TxBuild.{ BaseFee, InvokeHostFunction, HostFunction, - HostFunctionArgs, SCVal, + SCVec, SequenceNumber, Signature } @@ -24,20 +24,15 @@ alias Stellar.TxBuild.{ alias Stellar.Horizon.Accounts alias Stellar.KeyPair -contract_id = "5099ae2fa8453c363a9a71cdf8198ca258d12fa44bb5dc68ae0225595f461d37" -function_name = "hello" -args = [SCVal.new(string: "world")] - -function_args = - HostFunctionArgs.new( - type: :invoke, - contract_id: contract_id, - function_name: function_name, - args: args - ) +contract_address = + "CD3HNKU3ERTEYLBBBVTSOYE4ZL2ZWV7NHLQIZRRKC4CBNMZXC7ISBXHV" + |> SCAddress.new() + |> (&SCVal.new(address: &1)).() +function_name = SCVal.new(symbol: "hello") +args = SCVec.new([contract_address, function_name, SCVal.new(string: "dev")]) -function = HostFunction.new(args: function_args) -invoke_host_function_op = InvokeHostFunction.new(functions: [function]) +host_function = HostFunction.new(invoke_contract: args) +invoke_host_function_op = InvokeHostFunction.new(host_function: host_function) keypair = {public_key, _secret} = Stellar.KeyPair.from_secret_seed("SDR...Q24") source_account = Account.new(public_key) {:ok, seq_num} = Accounts.fetch_next_sequence_number(public_key) @@ -55,8 +50,8 @@ source_account soroban_data = "AAAAAgAAAAZQma4vqEU8Njqacc34GYyiWNEvpEu13GiuAiVZX0YdNwAAABQAAAAHRhmB7Imi4CwJhmzp1r/d76UShPJrO5PSHOV2Z9tPbE8AAAAAABJ8KwAAE3AAAAAAAAAAAAAAAAAAAAAAAAAAAA==" -min_resource_fee = 28_231 -fee = BaseFee.new(min_resource_fee + 100) +min_resource_fee = 51_470 +fee = BaseFee.new(min_resource_fee) # Use the XDR generated here to send it to the futurenet source_account @@ -73,12 +68,10 @@ source_account ```elixir alias Stellar.TxBuild.{ - ContractAuth, - AuthorizedInvocation, InvokeHostFunction, HostFunction, - HostFunctionArgs, SCVal, + SCVec, SCAddress, SequenceNumber, Signature @@ -87,38 +80,32 @@ alias Stellar.TxBuild.{ alias Stellar.Horizon.Accounts alias Stellar.KeyPair -contract_id = "5099ae2fa8453c363a9a71cdf8198ca258d12fa44bb5dc68ae0225595f461d37" -function_name = "inc" +contract_address = + "CD3HNKU3ERTEYLBBBVTSOYE4ZL2ZWV7NHLQIZRRKC4CBNMZXC7ISBXHV" + |> SCAddress.new() + |> (&SCVal.new(address: &1)).() +function_name = SCVal.new(symbol: "inc") keypair = {public_key, _secret} = Stellar.KeyPair.from_secret_seed("SDR...Q24") address_type = SCAddress.new(public_key) address = SCVal.new(address: address_type) -args = [address, SCVal.new(u128: %{hi: 0, lo: 2})] - -function_args = - HostFunctionArgs.new( - type: :invoke, - contract_id: contract_id, - function_name: function_name, - args: args - ) -auth_invocation = - AuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) +args = + SCVec.new([ + contract_address, + function_name, + address, + SCVal.new(u128: %{hi: 0, lo: 2}) + ]) -contract_auth = ContractAuth.new(authorized_invocation: auth_invocation) -function = HostFunction.new(args: function_args, auth: [contract_auth]) -invoke_host_function_op = InvokeHostFunction.new(functions: [function]) +host_function = HostFunction.new(invoke_contract: args) +invoke_host_function_op = InvokeHostFunction.new(host_function: host_function) source_account = Stellar.TxBuild.Account.new(public_key) {:ok, seq_num} = Accounts.fetch_next_sequence_number(public_key) sequence_number = SequenceNumber.new(seq_num) signature = Stellar.TxBuild.Signature.new(keypair) -# Use this XDR to simulate the transaction and get the soroban_data and min_resource_fee +# Use this XDR to simulate the transaction and get the soroban_data, the invoke_host_function auth +# and the min_resource_fee source_account |> Stellar.TxBuild.new(sequence_number: sequence_number) |> Stellar.TxBuild.add_operation(invoke_host_function_op) @@ -126,9 +113,14 @@ source_account # Simulate Transaction soroban_data = - "AAAAAgAAAAZQma4vqEU8Njqacc34GYyiWNEvpEu13GiuAiVZX0YdNwAAABQAAAAHRhmB7Imi4CwJhmzp1r/d76UShPJrO5PSHOV2Z9tPbE8AAAABAAAABlCZri+oRTw2OppxzfgZjKJY0S+kS7XcaK4CJVlfRh03AAAAEAAAAAEAAAACAAAADwAAAAdDb3VudGVyAAAAABMAAAAAAAAAAFo7IZ8b8ZTqK07QSVwodwWpVL59s3lsa3DTIMLBYrHaABOFdgAAFGQAAAD0AAAB6AAAAAAAAABgAAAAAA==" + "AAAAAAAAAAEAAAAHmDXys1KuBimD87u2AiUG/jb5CqOkQW/qASpb6gMVRlsAAAAAAAAAAQAAAAYAAAAB9naqmyRmTCwhDWcnYJzK9ZtX7TrgjMYqFwQWszcX0SAAAAAUAAAAAQAAAAAANnOcAAAUOAAAAQQAAAK8AAAAAAAAAIk=" -min_resource_fee = 60_839 +auth = [ + "AAAAAAAAAAAAAAAB9naqmyRmTCwhDWcnYJzK9ZtX7TrgjMYqFwQWszcX0SAAAAADaW5jAAAAAAIAAAASAAAAAAAAAABaOyGfG/GU6itO0ElcKHcFqVS+fbN5bGtw0yDCwWKx2gAAAAkAAAAAAAAAAAAAAAAAAAACAAAAAA==" +] + +invoke_host_function_op = InvokeHostFunction.set_auth(invoke_host_function_op, auth) +min_resource_fee = 78_281 fee = BaseFee.new(min_resource_fee + 100) # Use the XDR generated here to send it to the futurenet @@ -141,7 +133,7 @@ source_account |> Stellar.TxBuild.envelope() ``` -### With Stellar Account Authorization +### With Stellar Account Authorization (WIP: Preview 10 support) ```elixir alias StellarBase.XDR.{SorobanResources, SorobanTransactionData, UInt32} @@ -249,4 +241,4 @@ source_account |> Stellar.TxBuild.sign(signature) |> Stellar.TxBuild.envelope() -``` \ No newline at end of file +``` diff --git a/lib/tx_build/account_merge.ex b/lib/tx_build/account_merge.ex index 1ba2c253..74bd6c70 100644 --- a/lib/tx_build/account_merge.ex +++ b/lib/tx_build/account_merge.ex @@ -6,7 +6,7 @@ defmodule Stellar.TxBuild.AccountMerge do import Stellar.TxBuild.Validations, only: [validate_account: 1, validate_optional_account: 1] alias Stellar.TxBuild.{Account, OptionalAccount} - alias StellarBase.XDR.{OperationBody, OperationType, Operations.AccountMerge} + alias StellarBase.XDR.{OperationBody, OperationType} @behaviour Stellar.TxBuild.XDR @@ -35,7 +35,6 @@ defmodule Stellar.TxBuild.AccountMerge do destination |> Account.to_xdr() - |> AccountMerge.new() |> OperationBody.new(op_type) end end diff --git a/lib/tx_build/address_with_nonce.ex b/lib/tx_build/address_with_nonce.ex deleted file mode 100644 index 087514bd..00000000 --- a/lib/tx_build/address_with_nonce.ex +++ /dev/null @@ -1,56 +0,0 @@ -defmodule Stellar.TxBuild.AddressWithNonce do - @moduledoc """ - `AddressWithNonce` struct definition. - """ - - import Stellar.TxBuild.Validations, - only: [ - validate_pos_integer: 1 - ] - - alias Stellar.TxBuild.SCAddress - alias StellarBase.XDR.{AddressWithNonce, UInt64} - - @behaviour Stellar.TxBuild.XDR - - defstruct [:address, :nonce] - - @type validation :: {:ok, any()} | {:error, atom()} - - @type t :: %__MODULE__{address: SCAddress.t(), nonce: non_neg_integer()} - @impl true - def new(args, opts \\ nil) - - ## change functions to keyword list - def new(args, _opts) when is_list(args) do - address = Keyword.get(args, :address) - nonce = Keyword.get(args, :nonce) - - with {:ok, address} <- validate_address({:address, address}), - {:ok, nonce} <- validate_pos_integer({:nonce, nonce}) do - %__MODULE__{ - address: address, - nonce: nonce - } - end - end - - def new(_args, _opts), do: {:error, :invalid_address_with_nonce} - - @impl true - def to_xdr(%__MODULE__{ - address: address, - nonce: nonce - }) do - address = SCAddress.to_xdr(address) - nonce = UInt64.new(nonce) - - AddressWithNonce.new(address, nonce) - end - - def to_xdr(_error), do: {:error, :invalid_struct_address_with_nonce} - - @spec validate_address(tuple()) :: validation() - defp validate_address({_field, %SCAddress{} = value}), do: {:ok, value} - defp validate_address({field, _value}), do: {:error, :"invalid_#{field}"} -end diff --git a/lib/tx_build/authorized_invocation.ex b/lib/tx_build/authorized_invocation.ex deleted file mode 100644 index bc253307..00000000 --- a/lib/tx_build/authorized_invocation.ex +++ /dev/null @@ -1,84 +0,0 @@ -defmodule Stellar.TxBuild.AuthorizedInvocation do - @moduledoc """ - `AuthorizedInvocation` struct definition. - """ - import Stellar.TxBuild.Validations, - only: [ - validate_sc_vals: 1, - validate_contract_id: 1, - validate_string: 1, - is_struct?: 2 - ] - - alias StellarBase.XDR.{AuthorizedInvocation, AuthorizedInvocationList, Hash, SCSymbol, SCVec} - alias Stellar.TxBuild.SCVal - - @type error :: Keyword.t() | atom() - @type validation :: {:ok, any()} | {:error, error()} - @type authorized_invocation_list :: AuthorizedInvocationList.t() - @type t :: %__MODULE__{ - contract_id: binary(), - function_name: String.t(), - args: list(SCVal.t()), - sub_invocations: list(t()) - } - - @behaviour Stellar.TxBuild.XDR - - defstruct [:contract_id, :function_name, :args, :sub_invocations] - - @impl true - def new(args, opts \\ nil) - - def new(args, _opts) when is_list(args) do - contract_id = Keyword.get(args, :contract_id) - function_name = Keyword.get(args, :function_name) - sub_invocations = Keyword.get(args, :sub_invocations) - args = Keyword.get(args, :args) - - with {:ok, contract_id} <- validate_contract_id({:contract_id, contract_id}), - {:ok, function_name} <- validate_string({:function_name, function_name}), - {:ok, args} <- validate_sc_vals({:args, args}), - {:ok, sub_invocations} <- validate_sub_invocations({:sub_invocations, sub_invocations}) do - %__MODULE__{ - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: sub_invocations - } - end - end - - def new(_args, _opts), do: {:error, :invalid_authorized_invocation} - - @impl true - def to_xdr(%__MODULE__{ - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: sub_invocations - }) do - contract_id = - contract_id - |> Base.decode16!(case: :lower) - |> Hash.new() - - function_name = SCSymbol.new(function_name) - args = args |> Enum.map(&SCVal.to_xdr/1) |> SCVec.new() - - sub_invocations = sub_invocations |> Enum.map(&to_xdr/1) |> AuthorizedInvocationList.new() - - AuthorizedInvocation.new(contract_id, function_name, args, sub_invocations) - end - - def to_xdr(_error), do: {:error, :invalid_struct_authorized_invocation} - - @spec validate_sub_invocations(tuple :: tuple()) :: validation() - defp validate_sub_invocations({field, args}) when is_list(args) do - if Enum.all?(args, &is_struct?(&1, __MODULE__)), - do: {:ok, args}, - else: {:error, :"invalid_#{field}"} - end - - defp validate_sub_invocations({field, _args}), do: {:error, :"invalid_#{field}"} -end diff --git a/lib/tx_build/contract_auth.ex b/lib/tx_build/contract_auth.ex deleted file mode 100644 index f14dd603..00000000 --- a/lib/tx_build/contract_auth.ex +++ /dev/null @@ -1,206 +0,0 @@ -defmodule Stellar.TxBuild.ContractAuth do - @moduledoc """ - `ContractAuth` struct definition. - """ - - import Stellar.TxBuild.Validations, - only: [ - validate_sc_vals: 1, - validate_optional_address_with_nonce: 1 - ] - - alias Stellar.TxBuild.{ - AuthorizedInvocation, - OptionalAddressWithNonce, - SCMapEntry, - HashIDPreimage - } - - alias Stellar.{KeyPair, Network} - alias StellarBase.XDR.{ContractAuth, EnvelopeType, SCVec} - alias StellarBase.XDR.HashIDPreimage, as: HashIDPreimageXDR - alias StellarBase.XDR.Hash, as: HashXDR - alias StellarBase.XDR.HashIDPreimageContractAuth, as: HashIDPreimageContractAuthXDR - - alias Stellar.TxBuild.{ - AddressWithNonce, - SCVal, - HashIDPreimageContractAuth - } - - @type error :: Keyword.t() | atom() - @type validation :: {:ok, any()} | {:error, error()} - - @type t :: %__MODULE__{ - address_with_nonce: OptionalAddressWithNonce.t(), - authorized_invocation: AuthorizedInvocation.t(), - signature_args: list(SCVal.t()) - } - - @behaviour Stellar.TxBuild.XDR - - defstruct [:address_with_nonce, :authorized_invocation, :signature_args] - - @impl true - def new(args, opts \\ nil) - - def new(args, _opts) when is_list(args) do - address_with_nonce = Keyword.get(args, :address_with_nonce) - authorized_invocation = Keyword.get(args, :authorized_invocation) - signature_args = Keyword.get(args, :signature_args, []) - - with {:ok, opt_address_with_nonce} <- - validate_optional_address_with_nonce({:address_with_nonce, address_with_nonce}), - {:ok, authorized_invocation} <- - validate_authorized_invocation({:authorized_invocation, authorized_invocation}), - {:ok, signature_args} <- - validate_sc_vals({:signature_args, signature_args}) do - %__MODULE__{ - address_with_nonce: opt_address_with_nonce, - authorized_invocation: authorized_invocation, - signature_args: signature_args - } - end - end - - def new(_args, _opts), do: {:error, :invalid_contract_auth} - - @impl true - def to_xdr(%__MODULE__{ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation, - signature_args: signature_args - }) do - address_with_nonce = OptionalAddressWithNonce.to_xdr(address_with_nonce) - - authorized_invocation = AuthorizedInvocation.to_xdr(authorized_invocation) - - signature_args = - [vec: signature_args] - |> SCVal.new() - |> SCVal.to_xdr() - |> (&SCVec.new([&1])).() - - ContractAuth.new(address_with_nonce, authorized_invocation, signature_args) - end - - def to_xdr(_struct), do: {:error, :invalid_struct_contract_auth} - - @spec sign(contract_auth :: t(), secret_key :: binary) :: t() - def sign( - %__MODULE__{ - address_with_nonce: %OptionalAddressWithNonce{ - address_with_nonce: %AddressWithNonce{nonce: nonce} - }, - authorized_invocation: authorized_invocation, - signature_args: signature_args - } = contract_auth, - secret_key - ) - when is_binary(secret_key) do - {public_key, _secret_key} = KeyPair.from_secret_seed(secret_key) - raw_public_key = KeyPair.raw_public_key(public_key) - network_id = network_id_xdr() - - signature = - [ - network_id: network_id, - nonce: nonce, - invocation: authorized_invocation - ] - |> HashIDPreimageContractAuth.new() - |> (&HashIDPreimage.new(contract_auth: &1)).() - |> HashIDPreimage.to_xdr() - |> HashIDPreimageXDR.encode_xdr!() - |> hash() - |> KeyPair.sign(secret_key) - - public_key_map_entry = - SCMapEntry.new( - SCVal.new(symbol: "public_key"), - SCVal.new(bytes: raw_public_key) - ) - - signature_map_entry = - SCMapEntry.new( - SCVal.new(symbol: "signature"), - SCVal.new(bytes: signature) - ) - - signature_sc_val = SCVal.new(map: [public_key_map_entry, signature_map_entry]) - - %{contract_auth | signature_args: signature_args ++ [signature_sc_val]} - end - - def sign(_args, _val), do: {:error, :invalid_secret_key} - - @spec sign_xdr(base_64 :: binary(), secret_key :: binary()) :: binary() - def sign_xdr(base_64, secret_key) do - {public_key, _secret_key} = KeyPair.from_secret_seed(secret_key) - raw_public_key = KeyPair.raw_public_key(public_key) - network_id = network_id_xdr() - - {%ContractAuth{ - address_with_nonce: %{ - address_with_nonce: %{ - nonce: nonce - } - }, - authorized_invocation: authorized_invocation - } = contract_auth, - ""} = - base_64 - |> Base.decode64!() - |> ContractAuth.decode_xdr!() - - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_AUTH) - - signature = - network_id - |> HashXDR.new() - |> HashIDPreimageContractAuthXDR.new(nonce, authorized_invocation) - |> HashIDPreimageXDR.new(envelope_type) - |> HashIDPreimageXDR.encode_xdr!() - |> hash() - |> KeyPair.sign(secret_key) - - public_key_map_entry = - SCMapEntry.new( - SCVal.new(symbol: "public_key"), - SCVal.new(bytes: raw_public_key) - ) - - signature_map_entry = - SCMapEntry.new( - SCVal.new(symbol: "signature"), - SCVal.new(bytes: signature) - ) - - signature_args = [SCVal.new(map: [public_key_map_entry, signature_map_entry])] - - signature_xdr_val = - [vec: signature_args] - |> SCVal.new() - |> SCVal.to_xdr() - |> (&SCVec.new([&1])).() - - %{ - contract_auth - | signature_args: signature_xdr_val - } - |> ContractAuth.encode_xdr!() - |> Base.encode64() - end - - @spec network_id_xdr :: binary() - defp network_id_xdr, do: hash(Network.passphrase()) - - @spec hash(data :: binary()) :: binary() - defp hash(data), do: :crypto.hash(:sha256, data) - - @spec validate_authorized_invocation(tuple :: tuple()) :: validation() - defp validate_authorized_invocation({_field, %AuthorizedInvocation{} = value}), - do: {:ok, value} - - defp validate_authorized_invocation({field, _}), do: {:error, :"invalid_#{field}"} -end diff --git a/lib/tx_build/contract_executable.ex b/lib/tx_build/contract_executable.ex new file mode 100644 index 00000000..0eb37a7a --- /dev/null +++ b/lib/tx_build/contract_executable.ex @@ -0,0 +1,47 @@ +defmodule Stellar.TxBuild.ContractExecutable do + @moduledoc """ + `ContractExecutable` struct definition. + """ + + alias StellarBase.XDR.{ContractExecutable, ContractExecutableType, Hash, Void} + + @behaviour Stellar.TxBuild.XDR + + @type value :: String.t() | nil + @type type :: + :wasm_ref + | :token + @type t :: %__MODULE__{type: type(), value: value()} + + defstruct [:type, :value] + + @allowed_types ~w(wasm_ref token)a + + @impl true + def new(value, opts \\ []) + + def new(:token, _opts), do: %__MODULE__{type: :token, value: nil} + + def new([{type, value}], _opts) + when type in @allowed_types and is_binary(value) do + %__MODULE__{type: type, value: value} + end + + def new(_value, _opts), do: {:error, :invalid_contract_executable} + + @impl true + def to_xdr(%__MODULE__{type: :wasm_ref, value: value}) do + type = ContractExecutableType.new() + + value + |> Hash.new() + |> ContractExecutable.new(type) + end + + def to_xdr(%__MODULE__{type: :token, value: nil}) do + type = ContractExecutableType.new(:CONTRACT_EXECUTABLE_TOKEN) + ContractExecutable.new(Void.new(), type) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} +end diff --git a/lib/tx_build/contract_id_preimage.ex b/lib/tx_build/contract_id_preimage.ex new file mode 100644 index 00000000..73732a0e --- /dev/null +++ b/lib/tx_build/contract_id_preimage.ex @@ -0,0 +1,61 @@ +defmodule Stellar.TxBuild.ContractIDPreimage do + @moduledoc """ + `ContractIDPreimage` struct definition. + """ + alias StellarBase.XDR.ContractIDPreimage + alias StellarBase.XDR.ContractIDPreimageType + alias Stellar.TxBuild.{Asset, ContractIDPreimageFromAddress} + + @behaviour Stellar.TxBuild.XDR + + @type type :: :from_address | :from_asset + @type value :: Asset.t() | ContractIDPreimageFromAddress.t() + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type t :: %__MODULE__{ + type: type(), + value: value() + } + + defstruct [:type, :value] + + @allowed_types ~w(from_address from_asset)a + + @impl true + def new(value, opts \\ []) + + def new([{type, value}], _opts) when type in @allowed_types do + with {:ok, _value} <- validate_contract_id_preimage({type, value}) do + %__MODULE__{type: type, value: value} + end + end + + def new(_value, _opts), do: {:error, :invalid_contract_id_preimage} + + @impl true + def to_xdr(%__MODULE__{type: :from_address, value: value}) do + type = ContractIDPreimageType.new() + + value + |> ContractIDPreimageFromAddress.to_xdr() + |> ContractIDPreimage.new(type) + end + + def to_xdr(%__MODULE__{type: :from_asset, value: value}) do + type = ContractIDPreimageType.new(:CONTRACT_ID_PREIMAGE_FROM_ASSET) + + value + |> Asset.to_xdr() + |> ContractIDPreimage.new(type) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_contract_id_preimage({type :: atom(), value :: value()}) :: validation() + defp validate_contract_id_preimage({:from_asset, %Asset{} = value}), do: {:ok, value} + + defp validate_contract_id_preimage({:from_address, %ContractIDPreimageFromAddress{} = value}), + do: {:ok, value} + + defp validate_contract_id_preimage({type, _value}), do: {:error, :"invalid_#{type}"} +end diff --git a/lib/tx_build/contract_id_preimage_from_address.ex b/lib/tx_build/contract_id_preimage_from_address.ex new file mode 100644 index 00000000..52ac586a --- /dev/null +++ b/lib/tx_build/contract_id_preimage_from_address.ex @@ -0,0 +1,45 @@ +defmodule Stellar.TxBuild.ContractIDPreimageFromAddress do + @moduledoc """ + `ContractIDPreimageFromAddress` struct definition. + """ + + import Stellar.TxBuild.Validations, + only: [validate_address: 1] + + @behaviour Stellar.TxBuild.XDR + + alias StellarBase.XDR.{ContractIDPreimageFromAddress, UInt256} + alias Stellar.TxBuild.SCAddress + + defstruct [:address, :salt] + + @type address :: SCAddress.t() + @type salt :: binary() + @type t :: %__MODULE__{address: address(), salt: salt()} + + @impl true + def new(value, opts \\ []) + + def new( + [{:address, address}, {:salt, salt}], + _opts + ) + when is_binary(salt) do + with {:ok, address} <- validate_address(address) do + %__MODULE__{address: address, salt: salt} + end + end + + def new(_value, _opts), do: {:error, :invalid_contract_id_preimage_value} + + @impl true + def to_xdr(%__MODULE__{address: address, salt: salt}) do + salt = UInt256.new(salt) + + address + |> SCAddress.to_xdr() + |> ContractIDPreimageFromAddress.new(salt) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} +end diff --git a/lib/tx_build/create_contract_args.ex b/lib/tx_build/create_contract_args.ex new file mode 100644 index 00000000..67a22b44 --- /dev/null +++ b/lib/tx_build/create_contract_args.ex @@ -0,0 +1,70 @@ +defmodule Stellar.TxBuild.CreateContractArgs do + @moduledoc """ + `CreateContractArgs` struct definition. + """ + alias StellarBase.XDR.CreateContractArgs + alias Stellar.TxBuild.{ContractExecutable, ContractIDPreimage} + + @behaviour Stellar.TxBuild.XDR + + @type contract_id_preimage :: ContractIDPreimage.t() + @type contract_executable :: ContractExecutable.t() + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + + @type t :: %__MODULE__{ + contract_id_preimage: contract_id_preimage(), + contract_executable: contract_executable() + } + + defstruct [:contract_id_preimage, :contract_executable] + + @impl true + def new(args, opts \\ []) + + def new(args, _opts) when is_list(args) do + contract_id_preimage = Keyword.get(args, :contract_id_preimage) + contract_executable = Keyword.get(args, :contract_executable) + + with {:ok, contract_id_preimage} <- + validate_contract_id_preimage(contract_id_preimage), + {:ok, contract_executable} <- validate_contract_executable(contract_executable) do + %__MODULE__{ + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + } + end + end + + def new(_value, _opts), do: {:error, :invalid_args} + + @impl true + def to_xdr(%__MODULE__{ + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + }) do + contract_executable = ContractExecutable.to_xdr(contract_executable) + + contract_id_preimage + |> ContractIDPreimage.to_xdr() + |> CreateContractArgs.new(contract_executable) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_contract_id_preimage(contract_id_preimage :: contract_id_preimage()) :: + validation() + defp validate_contract_id_preimage(%ContractIDPreimage{} = contract_id_preimage), + do: {:ok, contract_id_preimage} + + defp validate_contract_id_preimage(_contract_id_preimage), + do: {:error, :invalid_contract_id_preimage} + + @spec validate_contract_executable(contract_executable :: contract_executable()) :: + validation() + defp validate_contract_executable(%ContractExecutable{} = contract_executable), + do: {:ok, contract_executable} + + defp validate_contract_executable(_contract_executable), + do: {:error, :invalid_contract_executable} +end diff --git a/lib/tx_build/hash_id_preimage.ex b/lib/tx_build/hash_id_preimage.ex index f961d93e..b98df14c 100644 --- a/lib/tx_build/hash_id_preimage.ex +++ b/lib/tx_build/hash_id_preimage.ex @@ -5,40 +5,36 @@ defmodule Stellar.TxBuild.HashIDPreimage do alias StellarBase.XDR.{EnvelopeType, HashIDPreimage} alias Stellar.TxBuild.{ - FromAsset, - HashIDPreimageCreateContractArgs, - HashIDPreimageContractAuth, - OperationID, - RevokeID, - Ed25519ContractID, - StructContractID, - SourceAccountContractID + HashIDPreimageContractID, + HashIDPreimageSorobanAuthorization, + HashIDPreimageOperationID, + HashIDPreimageRevokeID } @behaviour Stellar.TxBuild.XDR @type hash_id :: - OperationID.t() - | RevokeID.t() - | Ed25519ContractID.t() - | StructContractID.t() - | FromAsset.t() - | SourceAccountContractID.t() - | HashIDPreimageCreateContractArgs.t() - | HashIDPreimageContractAuth.t() - - @allowed_types ~w(op_id pool_revoke_op_id contract_id_from_ed25519 contract_id_from_contract contract_id_from_asset contact_id_from_source_acc create_contract_args contract_auth)a - + HashIDPreimageContractID.t() + | HashIDPreimageOperationID.t() + | HashIDPreimageRevokeID.t() + | HashIDPreimageSorobanAuthorization.t() @type validation :: {:ok, any()} | {:error, atom()} - @type t :: %__MODULE__{type: String.t(), value: hash_id()} + @type type :: + :op_id + | :pool_revoke_op_id + | :contract_id + | :soroban_auth + @type t :: %__MODULE__{type: type(), value: hash_id()} defstruct [:type, :value] + @allowed_types ~w(op_id pool_revoke_op_id contract_id soroban_auth)a + @impl true def new(args, opts \\ nil) def new([{type, value}], _opts) when type in @allowed_types do - with {:ok, _value} <- validate_hash_id_preimage({type, value}) do + with {:ok, value} <- validate_hash_id_preimage({type, value}) do %__MODULE__{ type: type, value: value @@ -51,116 +47,58 @@ defmodule Stellar.TxBuild.HashIDPreimage do @impl true def to_xdr(%__MODULE__{ type: :op_id, - value: %OperationID{} = value + value: %HashIDPreimageOperationID{} = value }) do envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_OP_ID) value - |> OperationID.to_xdr() + |> HashIDPreimageOperationID.to_xdr() |> HashIDPreimage.new(envelope_type) end def to_xdr(%__MODULE__{ type: :pool_revoke_op_id, - value: %RevokeID{} = value - }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_POOL_REVOKE_OP_ID) - - value - |> RevokeID.to_xdr() - |> HashIDPreimage.new(envelope_type) - end - - def to_xdr(%__MODULE__{ - type: :contract_id_from_ed25519, - value: %Ed25519ContractID{} = value - }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519) - - value - |> Ed25519ContractID.to_xdr() - |> HashIDPreimage.new(envelope_type) - end - - def to_xdr(%__MODULE__{ - type: :contract_id_from_contract, - value: %StructContractID{} = value + value: %HashIDPreimageRevokeID{} = value }) do envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_POOL_REVOKE_OP_ID) value - |> StructContractID.to_xdr() + |> HashIDPreimageRevokeID.to_xdr() |> HashIDPreimage.new(envelope_type) end def to_xdr(%__MODULE__{ - type: :contract_id_from_asset, - value: %FromAsset{} = value + type: :contract_id, + value: %HashIDPreimageContractID{} = value }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET) + envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_ID) value - |> FromAsset.to_xdr() + |> HashIDPreimageContractID.to_xdr() |> HashIDPreimage.new(envelope_type) end def to_xdr(%__MODULE__{ - type: :contact_id_from_source_acc, - value: %SourceAccountContractID{} = value + type: :soroban_auth, + value: %HashIDPreimageSorobanAuthorization{} = value }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT) + envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_SOROBAN_AUTHORIZATION) value - |> SourceAccountContractID.to_xdr() - |> HashIDPreimage.new(envelope_type) - end - - def to_xdr(%__MODULE__{ - type: :create_contract_args, - value: %HashIDPreimageCreateContractArgs{} = value - }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CREATE_CONTRACT_ARGS) - - value - |> HashIDPreimageCreateContractArgs.to_xdr() - |> HashIDPreimage.new(envelope_type) - end - - def to_xdr(%__MODULE__{ - type: :contract_auth, - value: %HashIDPreimageContractAuth{} = value - }) do - envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_CONTRACT_AUTH) - - value - |> HashIDPreimageContractAuth.to_xdr() + |> HashIDPreimageSorobanAuthorization.to_xdr() |> HashIDPreimage.new(envelope_type) end @spec validate_hash_id_preimage({atom(), hash_id()}) :: validation() - defp validate_hash_id_preimage({:op_id, %OperationID{} = value}), do: {:ok, value} - defp validate_hash_id_preimage({:pool_revoke_op_id, %RevokeID{} = value}), do: {:ok, value} + defp validate_hash_id_preimage({:op_id, %HashIDPreimageOperationID{} = value}), do: {:ok, value} - defp validate_hash_id_preimage({:contract_id_from_ed25519, %Ed25519ContractID{} = value}), + defp validate_hash_id_preimage({:pool_revoke_op_id, %HashIDPreimageRevokeID{} = value}), do: {:ok, value} - defp validate_hash_id_preimage({:contract_id_from_contract, %StructContractID{} = value}), + defp validate_hash_id_preimage({:contract_id, %HashIDPreimageContractID{} = value}), do: {:ok, value} - defp validate_hash_id_preimage({:contract_id_from_asset, %FromAsset{} = value}), - do: {:ok, value} - - defp validate_hash_id_preimage( - {:contact_id_from_source_acc, %SourceAccountContractID{} = value} - ), - do: {:ok, value} - - defp validate_hash_id_preimage( - {:create_contract_args, %HashIDPreimageCreateContractArgs{} = value} - ), - do: {:ok, value} - - defp validate_hash_id_preimage({:contract_auth, %HashIDPreimageContractAuth{} = value}), + defp validate_hash_id_preimage({:soroban_auth, %HashIDPreimageSorobanAuthorization{} = value}), do: {:ok, value} defp validate_hash_id_preimage({type, _value}), do: {:error, :"invalid_#{type}"} diff --git a/lib/tx_build/hash_id_preimage_contract_auth.ex b/lib/tx_build/hash_id_preimage_contract_auth.ex deleted file mode 100644 index b9248bfd..00000000 --- a/lib/tx_build/hash_id_preimage_contract_auth.ex +++ /dev/null @@ -1,68 +0,0 @@ -defmodule Stellar.TxBuild.HashIDPreimageContractAuth do - @moduledoc """ - `HashIDPreimageContractAuth` struct definition. - """ - - @type validation :: {:ok, any()} | {:error, atom()} - - import Stellar.TxBuild.Validations, - only: [ - validate_pos_integer: 1, - validate_string: 1 - ] - - alias StellarBase.XDR.{HashIDPreimageContractAuth, Hash, UInt64} - alias Stellar.TxBuild.AuthorizedInvocation - - @type t :: %__MODULE__{ - network_id: binary(), - nonce: non_neg_integer(), - invocation: AuthorizedInvocation.t() - } - - @behaviour Stellar.TxBuild.XDR - - defstruct [:network_id, :nonce, :invocation] - - @impl true - def new(args, opts \\ nil) - - def new(args, _opts) when is_list(args) do - network_id = Keyword.get(args, :network_id) - nonce = Keyword.get(args, :nonce) - invocation = Keyword.get(args, :invocation) - - with {:ok, network_id} <- validate_string({:network_id, network_id}), - {:ok, nonce} <- validate_pos_integer({:nonce, nonce}), - {:ok, invocation} <- validate_authorized_invocation({:invocation, invocation}) do - %__MODULE__{ - network_id: network_id, - nonce: nonce, - invocation: invocation - } - end - end - - def new(_args, _opts), do: {:error, :invalid_hash_id_preimage_contract_auth} - - @impl true - def to_xdr(%__MODULE__{ - network_id: network_id, - nonce: nonce, - invocation: invocation - }) do - network_id = Hash.new(network_id) - nonce = UInt64.new(nonce) - invocation = AuthorizedInvocation.to_xdr(invocation) - - HashIDPreimageContractAuth.new(network_id, nonce, invocation) - end - - def to_xdr(_error), do: {:error, :invalid_struct_hash_id_preimage_contract_auth} - - @spec validate_authorized_invocation(tuple :: tuple()) :: validation() - def validate_authorized_invocation({_field, %AuthorizedInvocation{} = value}), - do: {:ok, value} - - def validate_authorized_invocation({field, _}), do: {:error, :"invalid_#{field}"} -end diff --git a/lib/tx_build/hash_id_preimage_contract_id.ex b/lib/tx_build/hash_id_preimage_contract_id.ex new file mode 100644 index 00000000..59df698a --- /dev/null +++ b/lib/tx_build/hash_id_preimage_contract_id.ex @@ -0,0 +1,53 @@ +defmodule Stellar.TxBuild.HashIDPreimageContractID do + @moduledoc """ + `HashIDPreimageContractID` struct definition. + """ + alias StellarBase.XDR.Hash + alias Stellar.TxBuild.ContractIDPreimage + alias StellarBase.XDR.HashIDPreimageContractID + + @behaviour Stellar.TxBuild.XDR + + @type network_id :: String.t() + @type contract_id_preimage :: ContractIDPreimage.t() + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + + @type t :: %__MODULE__{network_id: network_id(), contract_id_preimage: contract_id_preimage()} + + defstruct [:network_id, :contract_id_preimage] + + @impl true + def new(args, opts \\ []) + + def new([{:network_id, network_id}, {:contract_id_preimage, contract_id_preimage}], _opts) + when is_binary(network_id) do + with {:ok, contract_id_preimage} <- validate_contract_id_preimage(contract_id_preimage) do + %__MODULE__{ + network_id: network_id, + contract_id_preimage: contract_id_preimage + } + end + end + + def new(_value, _opts), do: {:error, :invalid_hash_id_preimage_contract_id} + + @impl true + def to_xdr(%__MODULE__{network_id: network_id, contract_id_preimage: contract_id_preimage}) do + contract_id_preimage = ContractIDPreimage.to_xdr(contract_id_preimage) + + network_id + |> Hash.new() + |> HashIDPreimageContractID.new(contract_id_preimage) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_contract_id_preimage(contract_id_preimage :: contract_id_preimage()) :: + validation() + defp validate_contract_id_preimage(%ContractIDPreimage{} = contract_id_preimage), + do: {:ok, contract_id_preimage} + + defp validate_contract_id_preimage(_contract_id_preimage), + do: {:error, :invalid_contract_id_preimage} +end diff --git a/lib/tx_build/hash_id_preimage_create_contract_args.ex b/lib/tx_build/hash_id_preimage_create_contract_args.ex deleted file mode 100644 index 59bc9831..00000000 --- a/lib/tx_build/hash_id_preimage_create_contract_args.ex +++ /dev/null @@ -1,66 +0,0 @@ -defmodule Stellar.TxBuild.HashIDPreimageCreateContractArgs do - @moduledoc """ - `HashIDPreimageCreateContractArgs` struct definition. - """ - import Stellar.TxBuild.Validations, - only: [ - validate_pos_integer: 1, - validate_string: 1 - ] - - alias StellarBase.XDR.{HashIDPreimageCreateContractArgs, Hash, UInt256} - alias Stellar.TxBuild.SCContractExecutable - - @type validation :: {:ok, any()} | {:error, atom()} - @type t :: %__MODULE__{ - network_id: binary(), - executable: SCContractExecutable.t(), - salt: non_neg_integer() - } - - @behaviour Stellar.TxBuild.XDR - - defstruct [:network_id, :executable, :salt] - - @impl true - def new(args, opts \\ nil) - - def new(args, _opts) when is_list(args) do - network_id = Keyword.get(args, :network_id) - executable = Keyword.get(args, :executable) - salt = Keyword.get(args, :salt) - - with {:ok, network_id} <- validate_string({:network_id, network_id}), - {:ok, executable} <- validate_contract_code({:executable, executable}), - {:ok, salt} <- validate_pos_integer({:salt, salt}) do - %__MODULE__{ - network_id: network_id, - executable: executable, - salt: salt - } - end - end - - def new(_args, _opts), do: {:error, :invalid_hash_id_preimage_contract_args} - - @impl true - def to_xdr(%__MODULE__{ - network_id: network_id, - executable: executable, - salt: salt - }) do - network_id = Hash.new(network_id) - executable = SCContractExecutable.to_xdr(executable) - salt = UInt256.new(salt) - - HashIDPreimageCreateContractArgs.new(network_id, executable, salt) - end - - def to_xdr(_error), do: {:error, :invalid_struct_hash_id_preimage_contract_args} - - @spec validate_contract_code(tuple :: tuple()) :: validation() - defp validate_contract_code({_field, %SCContractExecutable{} = value}), - do: {:ok, value} - - defp validate_contract_code({field, _}), do: {:error, :"invalid_#{field}"} -end diff --git a/lib/tx_build/operation_id.ex b/lib/tx_build/hash_id_preimage_operation_id.ex similarity index 86% rename from lib/tx_build/operation_id.ex rename to lib/tx_build/hash_id_preimage_operation_id.ex index 6842a2d4..874f0f67 100644 --- a/lib/tx_build/operation_id.ex +++ b/lib/tx_build/hash_id_preimage_operation_id.ex @@ -1,6 +1,6 @@ -defmodule Stellar.TxBuild.OperationID do +defmodule Stellar.TxBuild.HashIDPreimageOperationID do @moduledoc """ - `OperationID` struct definition. + `HashIDPreimageOperationID` struct definition. """ import Stellar.TxBuild.Validations, only: [ @@ -10,7 +10,7 @@ defmodule Stellar.TxBuild.OperationID do ] alias Stellar.TxBuild.{AccountID, SequenceNumber} - alias StellarBase.XDR.{OperationID, UInt32} + alias StellarBase.XDR.{HashIDPreimageOperationID, UInt32} @type t :: %__MODULE__{ source_account: AccountID.t(), @@ -53,7 +53,7 @@ defmodule Stellar.TxBuild.OperationID do sequence_number = SequenceNumber.to_xdr(sequence_number) op_num = UInt32.new(op_num) - OperationID.new(source_account, sequence_number, op_num) + HashIDPreimageOperationID.new(source_account, sequence_number, op_num) end def to_xdr(_error), do: {:error, :invalid_struct_operation_id} diff --git a/lib/tx_build/revoke_id.ex b/lib/tx_build/hash_id_preimage_revoke_id.ex similarity index 89% rename from lib/tx_build/revoke_id.ex rename to lib/tx_build/hash_id_preimage_revoke_id.ex index 8388724c..079359b6 100644 --- a/lib/tx_build/revoke_id.ex +++ b/lib/tx_build/hash_id_preimage_revoke_id.ex @@ -1,6 +1,6 @@ -defmodule Stellar.TxBuild.RevokeID do +defmodule Stellar.TxBuild.HashIDPreimageRevokeID do @moduledoc """ - `RevokeID` struct definition. + `HashIDPreimageRevokeID` struct definition. """ import Stellar.TxBuild.Validations, only: [ @@ -11,7 +11,7 @@ defmodule Stellar.TxBuild.RevokeID do validate_asset: 1 ] - alias StellarBase.XDR.{RevokeID, UInt32} + alias StellarBase.XDR.{HashIDPreimageRevokeID, UInt32} alias Stellar.TxBuild.{AccountID, Asset, PoolID, SequenceNumber} @type t :: %__MODULE__{ @@ -67,7 +67,7 @@ defmodule Stellar.TxBuild.RevokeID do liquidity_pool_id = PoolID.to_xdr(liquidity_pool_id) asset = Asset.to_xdr(asset) - RevokeID.new(source_account, sequence_number, op_num, liquidity_pool_id, asset) + HashIDPreimageRevokeID.new(source_account, sequence_number, op_num, liquidity_pool_id, asset) end def to_xdr(_error), do: {:error, :invalid_struct_revoke_id} diff --git a/lib/tx_build/hash_id_preimage_soroban_authorization.ex b/lib/tx_build/hash_id_preimage_soroban_authorization.ex new file mode 100644 index 00000000..cf30bca6 --- /dev/null +++ b/lib/tx_build/hash_id_preimage_soroban_authorization.ex @@ -0,0 +1,100 @@ +defmodule Stellar.TxBuild.HashIDPreimageSorobanAuthorization do + @moduledoc """ + `HashIDPreimageSorobanAuthorization` struct definition. + """ + + alias Stellar.TxBuild.SorobanAuthorizedInvocation + + alias StellarBase.XDR.{ + Hash, + HashIDPreimageSorobanAuthorization, + Int64, + UInt32 + } + + @behaviour Stellar.TxBuild.XDR + + @type network_id :: String.t() + @type nonce :: non_neg_integer() + @type signature_expiration_ledger :: integer() + @type invocation :: SorobanAuthorizedInvocation.t() + @type validation :: {:ok, any()} | {:error, atom()} + + @type t :: %__MODULE__{ + network_id: network_id(), + nonce: nonce(), + signature_expiration_ledger: signature_expiration_ledger(), + invocation: invocation() + } + + defstruct [ + :network_id, + :nonce, + :signature_expiration_ledger, + :invocation + ] + + @impl true + def new(args, opts \\ []) + + def new(args, _opts) when is_list(args) do + network_id = Keyword.get(args, :network_id) + nonce = Keyword.get(args, :nonce) + signature_expiration_ledger = Keyword.get(args, :signature_expiration_ledger) + invocation = Keyword.get(args, :invocation) + + with {:ok, network_id} <- validate_network_id(network_id), + {:ok, nonce} <- validate_nonce(nonce), + {:ok, signature_expiration_ledger} <- + validate_signature_expiration_ledger(signature_expiration_ledger), + {:ok, invocation} <- validate_invocation(invocation) do + %__MODULE__{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + } + end + end + + def new(_args, _opts), do: {:error, :invalid_preimage_soroban_auth} + + @impl true + def to_xdr(%__MODULE__{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + }) do + nonce = Int64.new(nonce) + signature_expiration_ledger = UInt32.new(signature_expiration_ledger) + invocation = SorobanAuthorizedInvocation.to_xdr(invocation) + + network_id + |> Hash.new() + |> HashIDPreimageSorobanAuthorization.new(nonce, signature_expiration_ledger, invocation) + end + + def to_xdr(_error), do: {:error, :invalid_struct_revoke_id} + + @spec validate_network_id(network_id :: binary()) :: validation() + defp validate_network_id(network_id) when is_binary(network_id), do: {:ok, network_id} + defp validate_network_id(_network_id), do: {:error, :invalid_network_id} + + @spec validate_nonce(nonce :: integer()) :: validation() + defp validate_nonce(nonce) when is_integer(nonce), do: {:ok, nonce} + defp validate_nonce(_nonce), do: {:error, :invalid_nonce} + + @spec validate_signature_expiration_ledger(signature_expiration_ledger :: integer()) :: + validation() + defp validate_signature_expiration_ledger(signature_expiration_ledger) + when is_integer(signature_expiration_ledger), + do: {:ok, signature_expiration_ledger} + + defp validate_signature_expiration_ledger(_signature_expiration_ledger), + do: {:error, :invalid_signature_expiration_ledger} + + @spec validate_invocation(invocation :: invocation()) :: validation() + defp validate_invocation(%SorobanAuthorizedInvocation{} = invocation), do: {:ok, invocation} + defp validate_invocation(_invocation), do: {:error, :invalid_invocation} +end diff --git a/lib/tx_build/host_function.ex b/lib/tx_build/host_function.ex index c49d79ed..efac5b32 100644 --- a/lib/tx_build/host_function.ex +++ b/lib/tx_build/host_function.ex @@ -2,37 +2,36 @@ defmodule Stellar.TxBuild.HostFunction do @moduledoc """ `HostFunction` struct definition. """ - alias Stellar.TxBuild.{ContractAuth, HostFunctionArgs} - alias StellarBase.XDR.ContractAuthList - alias StellarBase.XDR.ContractAuth, as: ContractAuthXDR - alias StellarBase.XDR.HostFunction, as: HostFunctionXDR + alias Stellar.TxBuild.{CreateContractArgs, SCVec} + alias StellarBase.XDR.{HostFunction, HostFunctionType, VariableOpaque} @behaviour Stellar.TxBuild.XDR - @type args :: HostFunctionArgs.t() - @type contract_auth :: ContractAuth.t() - @type contract_auth_xdr :: ContractAuthXDR.t() - @type auth :: list(contract_auth()) | list(String.t()) + @type value :: CreateContractArgs.t() | SCVec.t() | binary() @type error :: {:error, atom()} @type validation :: {:ok, any()} | error() - + @type type :: + :invoke_contract + | :create_contract + | :upload_contract_wasm @type t :: %__MODULE__{ - args: args(), - auth: auth() + type: type(), + value: value() } - defstruct [:args, :auth] + defstruct [:type, :value] + + @allowed_types ~w(invoke_contract create_contract upload_contract_wasm)a @impl true def new(args, opts \\ []) - def new(args, _opts) when is_list(args) do - function_args = Keyword.get(args, :args) - auth = Keyword.get(args, :auth, []) - - with {:ok, args} <- validate_host_function_args(function_args), - {:ok, auth} <- validate_host_function_auth(auth) do - %__MODULE__{args: args, auth: auth} + def new([{type, value}], _opts) when type in @allowed_types do + with {:ok, _value} <- validate_host_function({type, value}) do + %__MODULE__{ + type: type, + value: value + } end end @@ -40,80 +39,44 @@ defmodule Stellar.TxBuild.HostFunction do @impl true def to_xdr(%__MODULE__{ - args: args, - auth: [%ContractAuth{} | _] = auth - }) - when is_list(auth) do - args_xdr = HostFunctionArgs.to_xdr(args) - - contract_auth = - auth - |> Enum.map(&ContractAuth.to_xdr/1) - |> ContractAuthList.new() - - HostFunctionXDR.new(args_xdr, contract_auth) + type: :invoke_contract, + value: value + }) do + type = HostFunctionType.new(:HOST_FUNCTION_TYPE_INVOKE_CONTRACT) + + value + |> SCVec.to_xdr() + |> HostFunction.new(type) end def to_xdr(%__MODULE__{ - args: args, - auth: auth - }) - when is_list(auth) do - args_xdr = HostFunctionArgs.to_xdr(args) - - contract_auth = - auth - |> Enum.map(&decode_contract_auth/1) - |> ContractAuthList.new() - - HostFunctionXDR.new(args_xdr, contract_auth) - end - - @spec set_auth(module :: t(), auth :: auth()) :: t() | error() - def set_auth(%__MODULE__{} = module, auth) when is_list(auth) do - with {:ok, auth} <- validate_auth_strings(auth) do - %{module | auth: auth} - end - end - - defp validate_auth_strings(auth) do - if Enum.all?(auth, &validate_xdr_string/1), - do: {:ok, auth}, - else: {:error, :invalid_auth} + type: :create_contract, + value: value + }) do + type = HostFunctionType.new(:HOST_FUNCTION_TYPE_CREATE_CONTRACT) + + value + |> CreateContractArgs.to_xdr() + |> HostFunction.new(type) end - @spec validate_xdr_string(xdr :: String.t() | nil) :: boolean() - defp validate_xdr_string(nil), do: true - - defp validate_xdr_string(xdr) when is_binary(xdr) do - case Base.decode64(xdr) do - {:ok, _} -> true - :error -> false - end - end - - @spec validate_host_function_args(args :: args()) :: validation() - defp validate_host_function_args(%HostFunctionArgs{} = args), do: {:ok, args} - defp validate_host_function_args(_args), do: {:error, :invalid_args} - - @spec validate_host_function_auth(auth :: auth()) :: validation() - defp validate_host_function_auth(auth) do - if Enum.all?(auth, &is_contract_auth?/1), - do: {:ok, auth}, - else: {:error, :invalid_auth} + def to_xdr(%__MODULE__{ + type: :upload_contract_wasm, + value: value + }) do + type = HostFunctionType.new(:HOST_FUNCTION_TYPE_UPLOAD_CONTRACT_WASM) + + value + |> VariableOpaque.new() + |> HostFunction.new(type) end - @spec is_contract_auth?(contract_auth :: contract_auth()) :: boolean() - defp is_contract_auth?(%ContractAuth{}), do: true - defp is_contract_auth?(_arg), do: false + @spec validate_host_function({type :: atom(), value :: value()}) :: validation() + defp validate_host_function({:invoke_contract, %SCVec{} = value}), do: {:ok, value} + defp validate_host_function({:create_contract, %CreateContractArgs{} = value}), do: {:ok, value} - @spec decode_contract_auth(auth :: String.t()) :: contract_auth_xdr() - defp decode_contract_auth(auth) do - {contract_auth, ""} = - auth - |> Base.decode64!() - |> ContractAuthXDR.decode_xdr!() + defp validate_host_function({:upload_contract_wasm, value}) when is_binary(value), + do: {:ok, value} - contract_auth - end + defp validate_host_function({type, _value}), do: {:error, :"invalid_#{type}"} end diff --git a/lib/tx_build/host_function_args.ex b/lib/tx_build/host_function_args.ex deleted file mode 100644 index 69918d90..00000000 --- a/lib/tx_build/host_function_args.ex +++ /dev/null @@ -1,223 +0,0 @@ -defmodule Stellar.TxBuild.HostFunctionArgs do - @moduledoc """ - `HostFunctionArgs` struct definition. - """ - - import Stellar.TxBuild.Validations, - only: [ - validate_sc_vals: 1, - validate_contract_id: 1, - validate_string: 1 - ] - - alias Stellar.TxBuild.{Asset, SCVal, SCContractExecutable} - alias StellarBase.XDR.HostFunctionArgs, as: HostFunctionArgsXDR - - alias StellarBase.XDR.{ - ContractID, - ContractIDType, - CreateContractArgs, - SCVec, - HostFunctionType, - UInt256, - UploadContractWasmArgs, - VariableOpaque256000 - } - - @behaviour Stellar.TxBuild.XDR - - @type type :: :invoke | :upload | :create - @type contract_id :: String.t() - @type function_name :: String.t() - @type invoke_args :: list(SCVal.t()) - @type args :: invoke_args() - @type wasm_id :: binary() - @type asset :: Asset.t() - @type error :: {:error, atom()} - @type validation :: {:ok, any()} | error() - - @type t :: %__MODULE__{ - type: type(), - contract_id: contract_id(), - function_name: function_name(), - args: args(), - code: binary(), - wasm_id: wasm_id(), - salt: binary(), - asset: asset() - } - - defstruct [:type, :contract_id, :function_name, :args, :code, :asset, :wasm_id, :salt] - - @impl true - def new(args, opts \\ []) - - def new( - [ - {:type, :invoke}, - {:contract_id, contract_id}, - {:function_name, function_name}, - {:args, args} - ], - _opts - ) - when is_list(args) do - with {:ok, contract_id} <- validate_contract_id({:contract_id, contract_id}), - {:ok, function_name} <- validate_string({:function_name, function_name}), - {:ok, args} <- validate_sc_vals({:args, args}) do - %__MODULE__{ - type: :invoke, - contract_id: contract_id, - function_name: function_name, - args: args - } - end - end - - def new( - [ - {:type, :upload}, - {:code, code} - ], - _opts - ) - when is_binary(code) do - %__MODULE__{ - type: :upload, - code: code - } - end - - def new( - [ - {:type, :create}, - {:wasm_id, wasm_id} - ], - _opts - ) do - new(type: :create, wasm_id: wasm_id, salt: :crypto.strong_rand_bytes(32)) - end - - def new( - [ - {:type, :create}, - {:wasm_id, wasm_id}, - {:salt, salt} - ], - _opts - ) do - with {:ok, wasm_id} <- validate_wasm_id(wasm_id), - {:ok, salt} <- validate_salt(salt) do - %__MODULE__{ - type: :create, - wasm_id: wasm_id, - salt: salt - } - end - end - - def new( - [ - {:type, :create}, - {:asset, asset} - ], - _opts - ) do - with {:ok, _asset} <- validate_asset(asset) do - %__MODULE__{ - type: :create, - asset: asset - } - end - end - - def new(_args, _opts), do: {:error, :invalid_operation_attributes} - - @impl true - def to_xdr(%__MODULE__{ - type: :invoke, - contract_id: contract_id, - function_name: function_name, - args: args - }) do - contract_id_scval = - contract_id - |> Base.decode16!(case: :lower) - |> (&SCVal.new(bytes: &1)).() - |> SCVal.to_xdr() - - sc_symbol_scval = - function_name - |> (&SCVal.new(symbol: &1)).() - |> SCVal.to_xdr() - - args_scvalxdr = Enum.map(args, &SCVal.to_xdr/1) - - sc_vec = - [contract_id_scval, sc_symbol_scval] - |> Kernel.++(args_scvalxdr) - |> SCVec.new() - - host_function_type = HostFunctionType.new() - HostFunctionArgsXDR.new(sc_vec, host_function_type) - end - - def to_xdr(%__MODULE__{ - type: :upload, - code: code - }) do - host_function_type = HostFunctionType.new(:HOST_FUNCTION_TYPE_UPLOAD_CONTRACT_WASM) - - code - |> VariableOpaque256000.new() - |> UploadContractWasmArgs.new() - |> HostFunctionArgsXDR.new(host_function_type) - end - - def to_xdr(%__MODULE__{ - type: :create, - wasm_id: wasm_id, - salt: salt, - asset: nil - }) do - host_function_type = HostFunctionType.new(:HOST_FUNCTION_TYPE_CREATE_CONTRACT) - - contract_id_type = ContractIDType.new(:CONTRACT_ID_FROM_SOURCE_ACCOUNT) - contract_id = salt |> UInt256.new() |> ContractID.new(contract_id_type) - - sc_contract_executable = - [wasm_ref: wasm_id] |> SCContractExecutable.new() |> SCContractExecutable.to_xdr() - - contract_id - |> CreateContractArgs.new(sc_contract_executable) - |> HostFunctionArgsXDR.new(host_function_type) - end - - def to_xdr(%__MODULE__{ - type: :create, - asset: asset - }) do - host_function_type = HostFunctionType.new(:HOST_FUNCTION_TYPE_CREATE_CONTRACT) - - contract_id_type = ContractIDType.new(:CONTRACT_ID_FROM_ASSET) - contract_id = asset |> Asset.to_xdr() |> ContractID.new(contract_id_type) - - sc_contract_executable = :token |> SCContractExecutable.new() |> SCContractExecutable.to_xdr() - - contract_id - |> CreateContractArgs.new(sc_contract_executable) - |> HostFunctionArgsXDR.new(host_function_type) - end - - @spec validate_asset(asset :: asset()) :: validation() - defp validate_asset(%Asset{} = asset), do: {:ok, asset} - defp validate_asset(_asset), do: {:error, :invalid_asset} - - @spec validate_salt(salt :: binary()) :: validation() - defp validate_salt(salt) when is_binary(salt) and byte_size(salt) == 32, do: {:ok, salt} - defp validate_salt(_salt), do: {:error, :invalid_salt} - - @spec validate_wasm_id(wasm_id :: binary()) :: validation() - defp validate_wasm_id(wasm_id) when is_binary(wasm_id), do: {:ok, wasm_id} - defp validate_wasm_id(_wasm_id), do: {:error, :invalid_wasm_id} -end diff --git a/lib/tx_build/invoke_host_function.ex b/lib/tx_build/invoke_host_function.ex index 79cbdb1c..be5f2fc8 100644 --- a/lib/tx_build/invoke_host_function.ex +++ b/lib/tx_build/invoke_host_function.ex @@ -1,46 +1,55 @@ defmodule Stellar.TxBuild.InvokeHostFunction do @moduledoc """ Performs the following operations: - - Invokes contract functions. + - Invokes contract host_functions. - Upload WASM of the new contracts. - Deploys new contracts using the uploaded WASM or built-in implementations. """ import Stellar.TxBuild.Validations, only: [validate_optional_account: 1] - alias Stellar.TxBuild.{HostFunction, OptionalAccount} + alias Stellar.TxBuild.{HostFunction, SorobanAuthorizationEntry, OptionalAccount} alias StellarBase.XDR.Operations.InvokeHostFunction alias StellarBase.XDR.{ - HostFunctionList100, OperationBody, - OperationType + OperationType, + SorobanAuthorizationEntryList } + alias StellarBase.XDR.SorobanAuthorizationEntry, as: SorobanAuthorizationEntryXDR + @behaviour Stellar.TxBuild.XDR - @type functions() :: list(HostFunction.t()) + @type auths :: list(SorobanAuthorizationEntry.t()) | list(String.t()) + @type error :: {:error, atom()} + @type host_function :: HostFunction.t() + @type soroban_auth_xdr :: SorobanAuthorizationEntryXDR.t() @type validation :: {:ok, any()} | {:error, atom()} @type t :: %__MODULE__{ - functions: functions(), + host_function: host_function(), + auths: auths(), source_account: OptionalAccount.t() } - defstruct [:functions, :source_account] + defstruct [:host_function, :auths, :source_account] @impl true - def new(functions, opts \\ []) + def new(host_function, opts \\ []) def new(args, _opts) when is_list(args) do - functions = Keyword.get(args, :functions) + host_function = Keyword.get(args, :host_function) + auths = Keyword.get(args, :auths, []) source_account = Keyword.get(args, :source_account) - with {:ok, functions} <- validate_host_function_list(functions), + with {:ok, host_function} <- validate_host_host_function(host_function), + {:ok, auths} <- validate_soroban_auth_entries(auths), {:ok, source_account} <- validate_optional_account({:source_account, source_account}) do %__MODULE__{ - functions: functions, + host_function: host_function, + auths: auths, source_account: source_account } end @@ -50,25 +59,88 @@ defmodule Stellar.TxBuild.InvokeHostFunction do @impl true def to_xdr(%__MODULE__{ - functions: functions + host_function: host_function, + auths: [%SorobanAuthorizationEntry{} | _] = auths }) do op_type = OperationType.new(:INVOKE_HOST_FUNCTION) + SCEC_INTERNAL_ERROR + + auth = + auths + |> Enum.map(&SorobanAuthorizationEntry.to_xdr/1) + |> SorobanAuthorizationEntryList.new() + + host_function + |> HostFunction.to_xdr() + |> InvokeHostFunction.new(auth) + |> OperationBody.new(op_type) + end + + def to_xdr(%__MODULE__{ + host_function: host_function, + auths: auths + }) + when is_list(auths) do + op_type = OperationType.new(:INVOKE_HOST_FUNCTION) + + auth = + auths + |> Enum.map(&decode_soroban_auth/1) + |> SorobanAuthorizationEntryList.new() - functions - |> Enum.map(&HostFunction.to_xdr/1) - |> HostFunctionList100.new() - |> InvokeHostFunction.new() + host_function + |> HostFunction.to_xdr() + |> InvokeHostFunction.new(auth) |> OperationBody.new(op_type) end - @spec validate_host_function_list(functions :: functions()) :: validation() - defp validate_host_function_list(functions) do - if Enum.all?(functions, &is_host_function?/1), - do: {:ok, functions}, - else: {:error, :invalid_host_function_list} + @spec set_auth(module :: t(), auths :: auths()) :: t() | error() + def set_auth(%__MODULE__{} = module, auths) when is_list(auths) do + with {:ok, auths} <- validate_auth_strings(auths) do + %{module | auths: auths} + end + end + + def set_auth(_module, _auths), do: {:error, :invalid_auth} + + defp validate_auth_strings(auth) do + if Enum.all?(auth, &validate_xdr_string/1), + do: {:ok, auth}, + else: {:error, :invalid_auth} + end + + @spec validate_xdr_string(xdr :: String.t() | nil) :: boolean() + defp validate_xdr_string(nil), do: true + + defp validate_xdr_string(xdr) when is_binary(xdr) do + case Base.decode64(xdr) do + {:ok, _} -> true + :error -> false + end + end + + @spec validate_host_host_function(host_function :: host_function()) :: validation() + defp validate_host_host_function(%HostFunction{} = host_function), do: {:ok, host_function} + defp validate_host_host_function(_host_function), do: {:error, :invalid_host_host_function} + + defp validate_soroban_auth_entries(auths) when is_list(auths) do + if Enum.all?(auths, &is_soroban_auth_entry?/1), + do: {:ok, auths}, + else: {:error, :invalid_soroban_auth_entries} end - @spec is_host_function?(function :: HostFunction.t()) :: boolean() - defp is_host_function?(%HostFunction{}), do: true - defp is_host_function?(_function), do: false + defp validate_soroban_auth_entries(_auths), do: {:error, :invalid_soroban_auth_entries} + + defp is_soroban_auth_entry?(%SorobanAuthorizationEntry{}), do: true + defp is_soroban_auth_entry?(_auth), do: false + + @spec decode_soroban_auth(auth :: String.t()) :: soroban_auth_xdr() + defp decode_soroban_auth(auth) do + {contract_auth, ""} = + auth + |> Base.decode64!() + |> SorobanAuthorizationEntryXDR.decode_xdr!() + + contract_auth + end end diff --git a/lib/tx_build/optional_address_with_nonce.ex b/lib/tx_build/optional_address_with_nonce.ex deleted file mode 100644 index 455b9346..00000000 --- a/lib/tx_build/optional_address_with_nonce.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Stellar.TxBuild.OptionalAddressWithNonce do - @moduledoc """ - `OptionalAddressWithNonce` struct definition. - """ - - alias StellarBase.XDR.OptionalAddressWithNonce - alias Stellar.TxBuild.AddressWithNonce - - @behaviour Stellar.TxBuild.XDR - - @type address_with_nonce :: AddressWithNonce.t() | nil - - @type t :: %__MODULE__{address_with_nonce: address_with_nonce()} - - defstruct [:address_with_nonce] - - @impl true - def new(address_with_nonce \\ nil, opts \\ []) - - def new(%AddressWithNonce{} = address_with_nonce, _opts), - do: %__MODULE__{address_with_nonce: address_with_nonce} - - def new(nil, _opts), do: %__MODULE__{address_with_nonce: nil} - - def new(_address_with_nonce, _opts), do: {:error, :invalid_optional_address_with_nonce} - - @impl true - def to_xdr(%__MODULE__{address_with_nonce: nil}), do: OptionalAddressWithNonce.new() - - def to_xdr(%__MODULE__{address_with_nonce: address_with_nonce}) do - address_with_nonce - |> AddressWithNonce.to_xdr() - |> OptionalAddressWithNonce.new() - end - - def to_xdr(_error), do: {:error, :invalid_struct_optional_address_with_nonce} -end diff --git a/lib/tx_build/sc_contract_executable.ex b/lib/tx_build/sc_contract_executable.ex deleted file mode 100644 index b2466cbe..00000000 --- a/lib/tx_build/sc_contract_executable.ex +++ /dev/null @@ -1,58 +0,0 @@ -defmodule Stellar.TxBuild.SCContractExecutable do - @moduledoc """ - `SCContractExecutable` struct definition. - """ - - @behaviour Stellar.TxBuild.XDR - - alias StellarBase.XDR.{Hash, SCContractExecutable, SCContractExecutableType, Void} - - @type type :: :wasm_ref | :token - @type value :: binary() | :token - @type validation :: {:ok, value()} | {:error, atom()} - @type t :: %__MODULE__{ - type: type(), - value: value() - } - - defstruct [:type, :value] - - @impl true - def new(args, opts \\ nil) - - def new(:token, _opts), do: %__MODULE__{type: :token, value: nil} - - def new([{:wasm_ref, value}], _opts) do - with {:ok, _value} <- validate_sc_contract_executable({:wasm_ref, value}) do - %__MODULE__{ - type: :wasm_ref, - value: value - } - end - end - - def new(_args, _opts), do: {:error, :invalid_sc_contract_executable} - - @impl true - def to_xdr(%__MODULE__{type: :wasm_ref, value: value}) do - type = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_WASM_REF) - - value - |> Hash.new() - |> SCContractExecutable.new(type) - end - - def to_xdr(%__MODULE__{type: :token, value: nil}) do - type = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_TOKEN) - void = Void.new() - - SCContractExecutable.new(void, type) - end - - def to_xdr(_error), do: {:error, :invalid_sc_contract_executable} - - @spec validate_sc_contract_executable(tuple()) :: validation() - defp validate_sc_contract_executable({:wasm_ref, value}) when is_binary(value), do: {:ok, value} - - defp validate_sc_contract_executable({:wasm_ref, _value}), do: {:error, :invalid_contract_hash} -end diff --git a/lib/tx_build/sc_error.ex b/lib/tx_build/sc_error.ex new file mode 100644 index 00000000..8613f920 --- /dev/null +++ b/lib/tx_build/sc_error.ex @@ -0,0 +1,88 @@ +defmodule Stellar.TxBuild.SCError do + @moduledoc """ + `ScErrorCode` struct definition. + """ + alias StellarBase.XDR.{SCError, SCErrorType, SCErrorCode} + + @behaviour Stellar.TxBuild.XDR + + @type code :: + :arith_domain + | :index_bounds + | :invalid_input + | :missing_value + | :existing_value + | :exceeded_limit + | :invalid_action + | :internal_error + | :unexpected_type + | :unexpected_size + @type type :: + :contract + | :wasm_vm + | :context + | :storage + | :object + | :crypto + | :events + | :budget + | :code + | :auth + + @type t :: %__MODULE__{type: type(), code: code()} + + defstruct [:type, :code] + + @types %{ + contract: :SCE_CONTRACT, + wasm_vm: :SCE_WASM_VM, + context: :SCE_CONTEXT, + storage: :SCE_STORAGE, + object: :SCE_OBJECT, + crypto: :SCE_CRYPTO, + events: :SCE_EVENTS, + budget: :SCE_BUDGET, + code: :SCE_VALUE, + auth: :SCE_AUTH + } + + @codes %{ + arith_domain: :SCEC_ARITH_DOMAIN, + index_bounds: :SCEC_INDEX_BOUNDS, + invalid_input: :SCEC_INVALID_INPUT, + missing_value: :SCEC_MISSING_VALUE, + existing_value: :SCEC_EXISTING_VALUE, + exceeded_limit: :SCEC_EXCEEDED_LIMIT, + invalid_action: :SCEC_INVALID_ACTION, + internal_error: :SCEC_INTERNAL_ERROR, + unexpected_type: :SCEC_UNEXPECTED_TYPE, + unexpected_size: :SCEC_UNEXPECTED_SIZE + } + + @impl true + def new(args, opts \\ []) + + def new([{type, code}], _opts) + when is_map_key(@types, type) and is_map_key(@codes, code) do + %__MODULE__{type: type, code: code} + end + + def new(_args, _opts), do: {:error, :invalid_sc_error} + + @impl true + def to_xdr(%__MODULE__{type: type, code: code}) do + with {:ok, type} <- retrieve_xdr_type(type), + {:ok, code} <- retrieve_xdr_code(code) do + code = SCErrorCode.new(code) + + type + |> SCErrorType.new() + |> SCError.new(code) + end + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + defp retrieve_xdr_type(type), do: {:ok, Map.get(@types, type)} + defp retrieve_xdr_code(code), do: {:ok, Map.get(@codes, code)} +end diff --git a/lib/tx_build/sc_status.ex b/lib/tx_build/sc_status.ex deleted file mode 100644 index 4846a5c3..00000000 --- a/lib/tx_build/sc_status.ex +++ /dev/null @@ -1,208 +0,0 @@ -defmodule Stellar.TxBuild.SCStatus do - @moduledoc """ - `SCStatus` struct definition. - """ - - @behaviour Stellar.TxBuild.XDR - - alias StellarBase.XDR.{ - SCUnknownErrorCode, - SCHostValErrorCode, - SCHostObjErrorCode, - SCHostFnErrorCode, - SCHostStorageErrorCode, - SCHostContextErrorCode, - SCVmErrorCode, - SCHostAuthErrorCode, - SCStatusType, - UInt32, - Void, - SCStatus - } - - @type validation :: {:ok, any()} | {:error, atom()} - - @type value :: - SCUnknownErrorCode.t() - | SCHostValErrorCode.t() - | SCHostObjErrorCode.t() - | SCHostFnErrorCode.t() - | SCHostStorageErrorCode.t() - | SCHostContextErrorCode.t() - | SCVmErrorCode.t() - | SCHostAuthErrorCode.t() - | SCStatusType.t() - | UInt32.t() - | Void.t() - - @type t :: %__MODULE__{ - type: String.t(), - value: value() - } - - @allowed_types ~w(ok unknown_error host_value_error host_object_error host_function_error host_storage_error host_context_error vm_error contract_error host_auth_error)a - - defstruct [:type, :value] - - @impl true - def new(args, opts \\ nil) - - def new([{type, value}], _opts) when type in @allowed_types do - with {:ok, _value} <- validate_sc_status({type, value}) do - %__MODULE__{ - type: type, - value: value - } - end - end - - def new(_args, _opts), do: {:error, :invalid_sc_val_type} - - @impl true - def to_xdr(%__MODULE__{type: :ok, value: value}) do - type = SCStatusType.new(:SST_OK) - - value - |> Void.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :unknown_error, value: value}) do - type = SCStatusType.new(:SST_UNKNOWN_ERROR) - - value - |> SCUnknownErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_value_error, value: value}) do - type = SCStatusType.new(:SST_HOST_VALUE_ERROR) - - value - |> SCHostValErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_object_error, value: value}) do - type = SCStatusType.new(:SST_HOST_OBJECT_ERROR) - - value - |> SCHostObjErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_function_error, value: value}) do - type = SCStatusType.new(:SST_HOST_FUNCTION_ERROR) - - value - |> SCHostFnErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_storage_error, value: value}) do - type = SCStatusType.new(:SST_HOST_STORAGE_ERROR) - - value - |> SCHostStorageErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_context_error, value: value}) do - type = SCStatusType.new(:SST_HOST_CONTEXT_ERROR) - - value - |> SCHostContextErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :vm_error, value: value}) do - type = SCStatusType.new(:SST_VM_ERROR) - - value - |> SCVmErrorCode.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :contract_error, value: value}) do - type = SCStatusType.new(:SST_CONTRACT_ERROR) - - value - |> UInt32.new() - |> SCStatus.new(type) - end - - def to_xdr(%__MODULE__{type: :host_auth_error, value: value}) do - type = SCStatusType.new(:SST_HOST_AUTH_ERROR) - - value - |> SCHostAuthErrorCode.new() - |> SCStatus.new(type) - end - - @spec validate_sc_status(tuple :: tuple()) :: validation() - def validate_sc_status({:ok, nil}), do: {:ok, nil} - def validate_sc_status({:ok, _value}), do: {:error, :invalid_void} - - def validate_sc_status({:unknown_error, value}) do - case value |> SCUnknownErrorCode.new() |> SCUnknownErrorCode.encode_xdr() do - {:ok, _unknown_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_unknown_error} - end - end - - def validate_sc_status({:host_value_error, value}) do - case value |> SCHostValErrorCode.new() |> SCHostValErrorCode.encode_xdr() do - {:ok, _host_value_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_value_error} - end - end - - def validate_sc_status({:host_object_error, value}) do - case value |> SCHostObjErrorCode.new() |> SCHostObjErrorCode.encode_xdr() do - {:ok, _host_object_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_object_error} - end - end - - def validate_sc_status({:host_function_error, value}) do - case value |> SCHostFnErrorCode.new() |> SCHostFnErrorCode.encode_xdr() do - {:ok, _host_function_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_function_error} - end - end - - def validate_sc_status({:host_storage_error, value}) do - case value |> SCHostStorageErrorCode.new() |> SCHostStorageErrorCode.encode_xdr() do - {:ok, _host_storage_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_storage_error} - end - end - - def validate_sc_status({:host_context_error, value}) do - case value |> SCHostContextErrorCode.new() |> SCHostContextErrorCode.encode_xdr() do - {:ok, _host_context_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_context_error} - end - end - - def validate_sc_status({:vm_error, value}) do - case value |> SCVmErrorCode.new() |> SCVmErrorCode.encode_xdr() do - {:ok, _vm_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_vm_error} - end - end - - def validate_sc_status({:contract_error, value}) do - case value |> UInt32.new() |> UInt32.encode_xdr() do - {:ok, _uint32} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_uint32} - end - end - - def validate_sc_status({:host_auth_error, value}) do - case value |> SCHostAuthErrorCode.new() |> SCHostAuthErrorCode.encode_xdr() do - {:ok, _host_auth_error} -> {:ok, value} - {:error, _reason} -> {:error, :invalid_host_auth_error} - end - end -end diff --git a/lib/tx_build/sc_val.ex b/lib/tx_build/sc_val.ex index 4c5606b0..9543386b 100644 --- a/lib/tx_build/sc_val.ex +++ b/lib/tx_build/sc_val.ex @@ -5,7 +5,8 @@ defmodule Stellar.TxBuild.SCVal do @behaviour Stellar.TxBuild.XDR - alias Stellar.TxBuild.{SCAddress, SCMapEntry, SCStatus} + alias StellarBase.XDR.SCContractInstance + alias Stellar.TxBuild.{SCAddress, SCError, SCMapEntry} alias StellarBase.XDR.{ Bool, @@ -16,8 +17,8 @@ defmodule Stellar.TxBuild.SCVal do Int32, Int64, SCBytes, - SCContractExecutable, - SCContractExecutableType, + ContractExecutable, + ContractExecutableType, SCMap, SCNonceKey, SCString, @@ -38,7 +39,7 @@ defmodule Stellar.TxBuild.SCVal do @type type :: :bool | :void - | :status + | :error | :u32 | :i32 | :u64 @@ -54,17 +55,17 @@ defmodule Stellar.TxBuild.SCVal do | :symbol | :vec | :map - | :contract | :address - | :ledger_key_contract + | :ledger_key_contract_instance | :ledger_key_nonce + | :contract_instance @type validation :: {:ok, any()} | {:error, atom()} @type value :: nil | integer() | boolean() - | SCStatus.t() + | SCError.t() | map() | binary() | list() @@ -78,11 +79,13 @@ defmodule Stellar.TxBuild.SCVal do defstruct [:type, :value] + @allowed_types ~w(bool void error u32 i32 u64 i64 time_point duration u128 i128 u256 i256 bytes string symbol vec map address ledger_key_contract_instance ledger_key_nonce contract_instance)a + @impl true def new(args, opts \\ nil) def new([{type, value}], _opts) - when type in ~w(bool void status u32 i32 u64 i64 time_point duration u128 i128 u256 i256 bytes string symbol vec map contract address ledger_key_contract ledger_key_nonce)a do + when type in @allowed_types do with {:ok, _value} <- validate_sc_val({type, value}) do %__MODULE__{ type: type, @@ -109,11 +112,11 @@ defmodule Stellar.TxBuild.SCVal do |> SCVal.new(type) end - def to_xdr(%__MODULE__{type: :status, value: value}) do - val_type = SCValType.new(:SCV_STATUS) + def to_xdr(%__MODULE__{type: :error, value: value}) do + val_type = SCValType.new(:SCV_ERROR) value - |> SCStatus.to_xdr() + |> SCError.to_xdr() |> SCVal.new(val_type) end @@ -275,23 +278,10 @@ defmodule Stellar.TxBuild.SCVal do |> SCVal.new(type) end - def to_xdr(%__MODULE__{type: :contract, value: {:wasm_ref, hash}}) do - type = SCValType.new(:SCV_CONTRACT_EXECUTABLE) - contract_code = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_WASM_REF) + def to_xdr(%__MODULE__{type: :ledger_key_contract_instance, value: nil}) do + type = SCValType.new(:SCV_LEDGER_KEY_CONTRACT_INSTANCE) - hash - |> Hash.new() - |> SCContractExecutable.new(contract_code) - |> SCVal.new(type) - end - - def to_xdr(%__MODULE__{type: :contract, value: :token}) do - type = SCValType.new(:SCV_CONTRACT_EXECUTABLE) - contract_code = SCContractExecutableType.new(:SCCONTRACT_EXECUTABLE_TOKEN) - - Void.new() - |> SCContractExecutable.new(contract_code) - |> SCVal.new(type) + SCVal.new(Void.new(), type) end def to_xdr(%__MODULE__{type: :address, value: value}) do @@ -302,10 +292,24 @@ defmodule Stellar.TxBuild.SCVal do |> SCVal.new(type) end - def to_xdr(%__MODULE__{type: :ledger_key_contract, value: _value}) do - type = SCValType.new(:SCV_LEDGER_KEY_CONTRACT_EXECUTABLE) + def to_xdr(%__MODULE__{type: :contract_instance, value: {:wasm_ref, hash}}) do + type = SCValType.new(:SCV_CONTRACT_INSTANCE) + contract_code = ContractExecutableType.new(:CONTRACT_EXECUTABLE_WASM) + + hash + |> Hash.new() + |> ContractExecutable.new(contract_code) + |> SCContractInstance.new(OptionalSCMap.new()) + |> SCVal.new(type) + end + + def to_xdr(%__MODULE__{type: :contract_instance, value: :token}) do + type = SCValType.new(:SCV_CONTRACT_INSTANCE) + contract_code = ContractExecutableType.new(:CONTRACT_EXECUTABLE_TOKEN) Void.new() + |> ContractExecutable.new(contract_code) + |> SCContractInstance.new(OptionalSCMap.new()) |> SCVal.new(type) end @@ -313,7 +317,7 @@ defmodule Stellar.TxBuild.SCVal do type = SCValType.new(:SCV_LEDGER_KEY_NONCE) value - |> SCAddress.to_xdr() + |> Int64.new() |> SCNonceKey.new() |> SCVal.new(type) end @@ -329,7 +333,7 @@ defmodule Stellar.TxBuild.SCVal do defp validate_sc_val({:bool, value}) when is_boolean(value), do: {:ok, value} defp validate_sc_val({:void, _value}), do: {:ok, nil} - defp validate_sc_val({:status, %SCStatus{} = value}), do: {:ok, value} + defp validate_sc_val({:error, %SCError{} = value}), do: {:ok, value} defp validate_sc_val({type, %{lo: lo, hi: hi} = value}) when type in ~w(u128 i128)a and is_integer(lo) and is_integer(hi), @@ -360,14 +364,14 @@ defmodule Stellar.TxBuild.SCVal do else: {:error, :invalid_map} end - defp validate_sc_val({:contract, :token}), do: {:ok, :token} + defp validate_sc_val({:contract_instance, :token}), do: {:ok, :token} - defp validate_sc_val({:contract, {:wasm_ref, hash} = value}) when is_binary(hash), + defp validate_sc_val({:contract_instance, {:wasm_ref, hash} = value}) when is_binary(hash), do: {:ok, value} defp validate_sc_val({:address, %SCAddress{} = value}), do: {:ok, value} - defp validate_sc_val({:ledger_key_contract, _value}), do: {:ok, nil} - defp validate_sc_val({:ledger_key_nonce, %SCAddress{} = value}), do: {:ok, value} + defp validate_sc_val({:ledger_key_contract_instance, _value}), do: {:ok, nil} + defp validate_sc_val({:ledger_key_nonce, value}) when is_integer(value), do: {:ok, value} defp validate_sc_val({type, _value}), do: {:error, :"invalid_#{type}"} @spec is_map_entry?(value :: any()) :: boolean() diff --git a/lib/tx_build/sc_vec.ex b/lib/tx_build/sc_vec.ex new file mode 100644 index 00000000..d8a583ed --- /dev/null +++ b/lib/tx_build/sc_vec.ex @@ -0,0 +1,52 @@ +defmodule Stellar.TxBuild.SCVec do + @moduledoc """ + `ScVec` struct definition. + """ + alias Stellar.TxBuild.SCVal + alias StellarBase.XDR.SCVec + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type items :: list(SCVal.t()) + + @type t :: %__MODULE__{items: items()} + + defstruct [:items] + + @impl true + def new(items, opts \\ []) + + def new(items, _opts) when is_list(items) do + with {:ok, items} <- validate_vec_items(items) do + %__MODULE__{items: items} + end + end + + def new(_items, _opts), do: {:error, :invalid_sc_vec} + + @impl true + def to_xdr(%__MODULE__{items: items}) do + items + |> Enum.map(&SCVal.to_xdr/1) + |> SCVec.new() + end + + @spec append_sc_val(t(), item :: SCVal.t()) :: t() | error() + def append_sc_val(%__MODULE__{items: items} = module, %SCVal{} = item), + do: %{module | items: items ++ [item]} + + def append_sc_val(_module, _item), do: {:error, :invalid_item} + + @spec validate_vec_items(items :: items()) :: validation() + defp validate_vec_items(items) do + if Enum.all?(items, &is_sc_val?/1), + do: {:ok, items}, + else: {:error, :invalid_vec} + end + + @spec is_sc_val?(value :: any()) :: boolean() + defp is_sc_val?(%SCVal{}), do: true + defp is_sc_val?(_), do: false +end diff --git a/lib/tx_build/soroban_address_credentials.ex b/lib/tx_build/soroban_address_credentials.ex new file mode 100644 index 00000000..8ccd7bea --- /dev/null +++ b/lib/tx_build/soroban_address_credentials.ex @@ -0,0 +1,80 @@ +defmodule Stellar.TxBuild.SorobanAddressCredentials do + @moduledoc """ + `SorobanAddressCredentials` struct definition. + """ + import Stellar.TxBuild.Validations, + only: [validate_address: 1, validate_vec: 1] + + alias StellarBase.XDR.{Int64, SorobanAddressCredentials, UInt32} + alias Stellar.TxBuild.{SCAddress, SCVec} + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type address :: SCAddress.t() + @type nonce :: non_neg_integer() + @type signature_expiration_ledger :: non_neg_integer() + @type signature_args :: SCVec.t() + + @type t :: %__MODULE__{ + address: address(), + nonce: nonce(), + signature_expiration_ledger: signature_expiration_ledger(), + signature_args: signature_args() + } + + defstruct [ + :address, + :nonce, + :signature_expiration_ledger, + :signature_args + ] + + @impl true + def new(args, opts \\ []) + + def new(args, _opts) when is_list(args) do + address = Keyword.get(args, :address) + nonce = Keyword.get(args, :nonce) + signature_expiration_ledger = Keyword.get(args, :signature_expiration_ledger) + signature_args = Keyword.get(args, :signature_args) + + with {:ok, address} <- validate_address(address), + {:ok, nonce} <- validate_integer({nonce, :nonce}), + {:ok, signature_expiration_ledger} <- + validate_integer({signature_expiration_ledger, :signature_expiration_ledger}), + {:ok, signature_args} <- validate_vec(signature_args) do + %__MODULE__{ + address: address, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + signature_args: signature_args + } + end + end + + def new(_args, _opts), do: {:error, :invalid_soroban_address_args} + + @impl true + def to_xdr(%__MODULE__{ + address: address, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + signature_args: signature_args + }) do + nonce = Int64.new(nonce) + signature_expiration_ledger = UInt32.new(signature_expiration_ledger) + signature_args = SCVec.to_xdr(signature_args) + + address + |> SCAddress.to_xdr() + |> SorobanAddressCredentials.new(nonce, signature_expiration_ledger, signature_args) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_integer(tuple()) :: validation() + defp validate_integer({integer, _type}) when is_integer(integer), do: {:ok, integer} + defp validate_integer({_integer, type}), do: {:error, :"invalid_#{type}"} +end diff --git a/lib/tx_build/soroban_authorization_entry.ex b/lib/tx_build/soroban_authorization_entry.ex new file mode 100644 index 00000000..93b4eec6 --- /dev/null +++ b/lib/tx_build/soroban_authorization_entry.ex @@ -0,0 +1,68 @@ +defmodule Stellar.TxBuild.SorobanAuthorizationEntry do + @moduledoc """ + `SorobanAuthorizationEntry` struct definition. + """ + + alias Stellar.TxBuild.{ + SorobanCredentials, + SorobanAuthorizedInvocation + } + + alias StellarBase.XDR.SorobanAuthorizationEntry + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type credentials :: SorobanCredentials.t() + @type root_invocation :: SorobanAuthorizedInvocation.t() + + @type t :: %__MODULE__{ + credentials: credentials(), + root_invocation: root_invocation() + } + + defstruct [:credentials, :root_invocation] + + @impl true + def new(value, opts \\ []) + + def new(args, _opts) when is_list(args) do + credentials = Keyword.get(args, :credentials) + root_invocation = Keyword.get(args, :root_invocation) + + with {:ok, credentials} <- validate_credentials(credentials), + {:ok, root_invocation} <- validate_root_invocation(root_invocation) do + %__MODULE__{ + credentials: credentials, + root_invocation: root_invocation + } + end + end + + def new(_value, _opts), do: {:error, :invalid_auth_entry_args} + + @impl true + def to_xdr(%__MODULE__{ + credentials: credentials, + root_invocation: root_invocation + }) do + root_invocation = SorobanAuthorizedInvocation.to_xdr(root_invocation) + + credentials + |> SorobanCredentials.to_xdr() + |> SorobanAuthorizationEntry.new(root_invocation) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_credentials(credentials :: credentials()) :: validation() + defp validate_credentials(%SorobanCredentials{} = credentials), do: {:ok, credentials} + defp validate_credentials(_credentials), do: {:error, :invalid_credentials} + + @spec validate_root_invocation(root_invocation :: root_invocation()) :: validation() + defp validate_root_invocation(%SorobanAuthorizedInvocation{} = root_invocation), + do: {:ok, root_invocation} + + defp validate_root_invocation(_root_invocation), do: {:error, :invalid_root_invocation} +end diff --git a/lib/tx_build/soroban_authorized_contract_function.ex b/lib/tx_build/soroban_authorized_contract_function.ex new file mode 100644 index 00000000..37c345f7 --- /dev/null +++ b/lib/tx_build/soroban_authorized_contract_function.ex @@ -0,0 +1,70 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedContractFunction do + @moduledoc """ + `SorobanAuthorizedContractFunction` struct definition. + """ + + import Stellar.TxBuild.Validations, + only: [validate_vec: 1, validate_address: 1] + + alias StellarBase.XDR.{SorobanAuthorizedContractFunction, SCSymbol} + alias Stellar.TxBuild.{SCAddress, SCVec} + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type contract_address :: SCAddress.t() + @type function_name :: String.t() + @type args :: SCVec.t() + + @type t :: %__MODULE__{ + contract_address: contract_address(), + function_name: function_name(), + args: args() + } + + defstruct [:contract_address, :function_name, :args] + + @impl true + def new(args, opts \\ []) + + def new(args, _opts) when is_list(args) do + contract_address = Keyword.get(args, :contract_address) + function_name = Keyword.get(args, :function_name) + function_args = Keyword.get(args, :args) + + with {:ok, contract_address} <- validate_address(contract_address), + {:ok, function_name} <- validate_function_name(function_name), + {:ok, function_args} <- validate_vec(function_args) do + %__MODULE__{ + contract_address: contract_address, + function_name: function_name, + args: function_args + } + end + end + + def new(_value, _opts), do: {:error, :invalid_soroban_auth_contract_function_args} + + @impl true + def to_xdr(%__MODULE__{ + contract_address: contract_address, + function_name: function_name, + args: args + }) do + function_name = SCSymbol.new(function_name) + args = SCVec.to_xdr(args) + + contract_address + |> SCAddress.to_xdr() + |> SorobanAuthorizedContractFunction.new(function_name, args) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_function_name(function_name :: function_name()) :: validation() + defp validate_function_name(function_name) when is_binary(function_name), + do: {:ok, function_name} + + defp validate_function_name(_function_name), do: {:error, :invalid_function_name} +end diff --git a/lib/tx_build/soroban_authorized_function.ex b/lib/tx_build/soroban_authorized_function.ex new file mode 100644 index 00000000..6b9dea8e --- /dev/null +++ b/lib/tx_build/soroban_authorized_function.ex @@ -0,0 +1,61 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedFunction do + @moduledoc """ + `SorobanAuthorizedFunction` struct definition. + """ + alias StellarBase.XDR.{SorobanAuthorizedFunction, SorobanAuthorizedFunctionType} + alias Stellar.TxBuild.{CreateContractArgs, SorobanAuthorizedContractFunction} + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type type :: :contract_fn | :create_contract_host_fn + @type value :: CreateContractArgs.t() | SorobanAuthorizedContractFunction.t() + @type t :: %__MODULE__{type: type(), value: value()} + + defstruct [:type, :value] + + @allowed_types ~w(contract_fn create_contract_host_fn)a + + @impl true + def new(value, opts \\ []) + + def new([{type, value}], _opts) when type in @allowed_types do + with {:ok, value} <- validate_soroban_auth_function({type, value}) do + %__MODULE__{type: type, value: value} + end + end + + def new(_value, _opts), do: {:error, :invalid_soroban_auth_function} + + @impl true + def to_xdr(%__MODULE__{type: :contract_fn, value: value}) do + type = SorobanAuthorizedFunctionType.new() + + value + |> SorobanAuthorizedContractFunction.to_xdr() + |> SorobanAuthorizedFunction.new(type) + end + + def to_xdr(%__MODULE__{type: :create_contract_host_fn, value: value}) do + type = + SorobanAuthorizedFunctionType.new(:SOROBAN_AUTHORIZED_FUNCTION_TYPE_CREATE_CONTRACT_HOST_FN) + + value + |> CreateContractArgs.to_xdr() + |> SorobanAuthorizedFunction.new(type) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_soroban_auth_function(tuple()) :: validation() + defp validate_soroban_auth_function( + {:contract_fn, %SorobanAuthorizedContractFunction{} = value} + ), + do: {:ok, value} + + defp validate_soroban_auth_function({:create_contract_host_fn, %CreateContractArgs{} = value}), + do: {:ok, value} + + defp validate_soroban_auth_function({type, _value}), do: {:error, :"invalid_#{type}"} +end diff --git a/lib/tx_build/soroban_authorized_invocation.ex b/lib/tx_build/soroban_authorized_invocation.ex new file mode 100644 index 00000000..b180c3a2 --- /dev/null +++ b/lib/tx_build/soroban_authorized_invocation.ex @@ -0,0 +1,63 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedInvocation do + @moduledoc """ + `SorobanAuthorizedInvocation` struct definition. + """ + + alias Stellar.TxBuild.SorobanAuthorizedFunction + alias StellarBase.XDR.{SorobanAuthorizedInvocation, SorobanAuthorizedInvocationList} + + @behaviour Stellar.TxBuild.XDR + + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type soroban_function :: SorobanAuthorizedFunction.t() + @type sub_invocations :: list(SorobanAuthorizedInvocation.t()) + + @type t :: %__MODULE__{function: soroban_function(), sub_invocations: sub_invocations()} + + defstruct [:function, :sub_invocations] + + @impl true + def new(args, opts \\ []) + + def new(args, _opts) when is_list(args) do + function = Keyword.get(args, :function) + sub_invocations = Keyword.get(args, :sub_invocations) + + with {:ok, function} <- validate_function(function), + {:ok, sub_invocations} <- validate_sub_invocations(sub_invocations) do + %__MODULE__{function: function, sub_invocations: sub_invocations} + end + end + + def new(_args, _opts), do: {:error, :invalid_soroban_auth_invocation} + + @impl true + def to_xdr(%__MODULE__{function: function, sub_invocations: sub_invocations}) do + sub_invocations = + sub_invocations + |> Enum.map(&to_xdr/1) + |> SorobanAuthorizedInvocationList.new() + + function + |> SorobanAuthorizedFunction.to_xdr() + |> SorobanAuthorizedInvocation.new(sub_invocations) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_function(function :: soroban_function()) :: validation() + defp validate_function(%SorobanAuthorizedFunction{} = function), do: {:ok, function} + defp validate_function(_function), do: {:error, :invalid_function} + + @spec validate_sub_invocations(sub_invocations :: sub_invocations()) :: validation() + defp validate_sub_invocations(sub_invocations) do + if Enum.all?(sub_invocations, &is_soroban_auth_invocation?/1), + do: {:ok, sub_invocations}, + else: {:error, :invalid_sub_invocations} + end + + @spec is_soroban_auth_invocation?(t()) :: boolean() + defp is_soroban_auth_invocation?(%__MODULE__{}), do: true + defp is_soroban_auth_invocation?(_struct), do: false +end diff --git a/lib/tx_build/soroban_credentials.ex b/lib/tx_build/soroban_credentials.ex new file mode 100644 index 00000000..992441ac --- /dev/null +++ b/lib/tx_build/soroban_credentials.ex @@ -0,0 +1,52 @@ +defmodule Stellar.TxBuild.SorobanCredentials do + @moduledoc """ + `SorobanCredentials` struct definition. + """ + alias StellarBase.XDR.{SorobanCredentials, SorobanCredentialsType, Void} + alias Stellar.TxBuild.SorobanAddressCredentials + + @behaviour Stellar.TxBuild.XDR + + @type value :: SorobanAddressCredentials.t() | nil + @type error :: {:error, atom()} + @type validation :: {:ok, any()} | error() + @type type :: :source_account | :address + @type t :: %__MODULE__{type: type(), value: value()} + + defstruct [:type, :value] + + @allowed_types ~w(source_account address)a + + @impl true + def new(value, opts \\ []) + + def new([{type, value}], _opts) when type in @allowed_types do + with {:ok, value} <- validate_soroban_credentials({type, value}) do + %__MODULE__{type: type, value: value} + end + end + + def new(_value, _opts), do: {:error, :invalid_soroban_credential} + + @impl true + def to_xdr(%__MODULE__{type: :source_account, value: nil}), + do: SorobanCredentials.new(Void.new(), SorobanCredentialsType.new()) + + def to_xdr(%__MODULE__{type: :address, value: value}) do + type = SorobanCredentialsType.new(:SOROBAN_CREDENTIALS_ADDRESS) + + value + |> SorobanAddressCredentials.to_xdr() + |> SorobanCredentials.new(type) + end + + def to_xdr(_struct), do: {:error, :invalid_struct} + + @spec validate_soroban_credentials(tuple()) :: validation() + defp validate_soroban_credentials({:source_account, nil}), do: {:ok, nil} + + defp validate_soroban_credentials({:address, %SorobanAddressCredentials{} = value}), + do: {:ok, value} + + defp validate_soroban_credentials({type, _value}), do: {:error, :"invalid_#{type}"} +end diff --git a/lib/tx_build/validations.ex b/lib/tx_build/validations.ex index 40a6acf0..5d1c712a 100644 --- a/lib/tx_build/validations.ex +++ b/lib/tx_build/validations.ex @@ -17,14 +17,15 @@ defmodule Stellar.TxBuild.Validations do OptionalWeight, OptionalSigner, OptionalString32, - OptionalAddressWithNonce, PoolID, Price, SequenceNumber, Signer, String32, Weight, - SCVal + SCAddress, + SCVal, + SCVec } @type account_id :: String.t() @@ -196,14 +197,6 @@ defmodule Stellar.TxBuild.Validations do def validate_contract_id({field, _contract_id}), do: {:error, :"invalid_#{field}"} - @spec validate_optional_address_with_nonce(component :: component()) :: validation() - def validate_optional_address_with_nonce({field, value}) do - case OptionalAddressWithNonce.new(value) do - %OptionalAddressWithNonce{} = opt_address_with_nonce -> {:ok, opt_address_with_nonce} - {:error, _reason} -> {:error, :"invalid_#{field}"} - end - end - @spec validate_string(tuple()) :: validation() def validate_string({_type, string}) when is_binary(string), do: {:ok, string} def validate_string({type, _string}), do: {:error, :"invalid_#{type}"} @@ -213,4 +206,13 @@ defmodule Stellar.TxBuild.Validations do do: {:ok, value} def validate_sequence_number({field, _}), do: {:error, :"invalid_#{field}"} + + @spec validate_address(address :: SCAddress.t()) :: validation() + def validate_address(%SCAddress{} = address), do: {:ok, address} + + def validate_address(_address), do: {:error, :invalid_address} + + @spec validate_vec(args :: SCVec.t()) :: validation() + def validate_vec(%SCVec{} = args), do: {:ok, args} + def validate_vec(_args), do: {:error, :invalid_args} end diff --git a/lib/tx_build/variable_opaque.ex b/lib/tx_build/variable_opaque.ex new file mode 100644 index 00000000..b26322ba --- /dev/null +++ b/lib/tx_build/variable_opaque.ex @@ -0,0 +1,25 @@ +defmodule Stellar.TxBuild.VariableOpaque do + @moduledoc """ + `VariableOpaque` struct definition. + """ + alias StellarBase.XDR.VariableOpaque + + @behaviour Stellar.TxBuild.XDR + + @type value :: String.t() + + @type t :: %__MODULE__{value: value()} + + defstruct [:value] + + @impl true + def new(value, opts \\ []) + + def new(value, _opts) when is_binary(value), do: %__MODULE__{value: value} + + def new(_value, _opts), do: {:error, :invalid_opaque} + + @impl true + def to_xdr(%__MODULE__{value: value}), do: VariableOpaque.new(value) + def to_xdr(_struct), do: {:error, :invalid_struct} +end diff --git a/mix.exs b/mix.exs index 1a9d5287..a3e64fe9 100644 --- a/mix.exs +++ b/mix.exs @@ -2,7 +2,7 @@ defmodule Stellar.MixProject do use Mix.Project @github_url "https://github.com/kommitters/stellar_sdk" - @version "0.15.1" + @version "0.16.0" def project do [ @@ -37,14 +37,14 @@ defmodule Stellar.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:stellar_base, "~> 0.11.1"}, + {:stellar_base, "~> 0.12"}, {:ed25519, "~> 1.3"}, {:hackney, "~> 1.17"}, {:jason, "~> 1.0"}, {:dialyxir, "~> 1.0", only: [:dev], runtime: false}, {:excoveralls, "~> 0.16", only: :test}, {:credo, "~> 1.5", only: [:dev, :test], runtime: false}, - {:ex_doc, "~> 0.29", only: :dev, runtime: false} + {:ex_doc, "~> 0.30", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index 1fcf19bf..7e035bd8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,15 +1,15 @@ %{ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, - "crc": {:hex, :crc, "0.10.4", "06f5f54e2ec2954968703dcd37d7a4c65cee7a5305c48a23c509dc20a5469d4f", [:mix, :rebar3], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "90bdd5b5ac883f0b1860692324ed3f53fdaa6f1e8483771873fea07e71def91d"}, + "crc": {:hex, :crc, "0.10.5", "ee12a7c056ac498ef2ea985ecdc9fa53c1bfb4e53a484d9f17ff94803707dfd8", [:mix, :rebar3], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3e673b6495a9525c5c641585af1accba59a1eb33de697bedf341e247012c2c7f"}, "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, "ed25519": {:hex, :ed25519, "1.4.1", "479fb83c3e31987c9cad780e6aeb8f2015fb5a482618cdf2a825c9aff809afc4", [:mix], [], "hexpm", "0dacb84f3faa3d8148e81019ca35f9d8dcee13232c32c9db5c2fb8ff48c80ec7"}, - "elixir_make": {:hex, :elixir_make, "0.7.6", "67716309dc5d43e16b5abbd00c01b8df6a0c2ab54a8f595468035a50189f9169", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5a0569756b0f7873a77687800c164cca6dfc03a09418e6fcf853d78991f49940"}, + "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, "elixir_xdr": {:hex, :elixir_xdr, "0.3.9", "d9c461a1c04bc31ccb36114b606c750d0ba0bed0a1d7ffc35d206e58faaba0ba", [:mix], [], "hexpm", "30afac1a82fafe11708e14d92532a83a881d1004ec92bf00e3d8a827c6685e3d"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, + "ex_doc": {:hex, :ex_doc, "0.30.3", "bfca4d340e3b95f2eb26e72e4890da83e2b3a5c5b0e52607333bf5017284b063", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "fbc8702046c1d25edf79de376297e608ac78cdc3a29f075484773ad1718918b6"}, "excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, @@ -17,12 +17,12 @@ "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "stellar_base": {:hex, :stellar_base, "0.11.1", "c53c12913885f1657d386cc7ed17f7db3f5f1d5bb5a545857b7950cf6bbc6da7", [:mix], [{:crc, "~> 0.10.0", [hex: :crc, repo: "hexpm", optional: false]}, {:elixir_xdr, "~> 0.3.0", [hex: :elixir_xdr, repo: "hexpm", optional: false]}], "hexpm", "c69b01316c5b1cdaa2bdc5e22ae0bbbfd34483fbb2acb8c3aab71781227837ec"}, + "stellar_base": {:hex, :stellar_base, "0.12.0", "2a7b926d64fbfb934d5f09014fd2da96983e87f677c648a816445bc7064111a6", [:mix], [{:crc, "~> 0.10.0", [hex: :crc, repo: "hexpm", optional: false]}, {:elixir_xdr, "~> 0.3.9", [hex: :elixir_xdr, repo: "hexpm", optional: false]}], "hexpm", "22cc15ad9efc011637a7583e20e91bd8b3d3a32133108a2b1a04487bd80ca91e"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } diff --git a/test/support/fixtures/xdr/claimable_balances.ex b/test/support/fixtures/xdr/claimable_balances.ex index cace6a3b..9fae2eb3 100644 --- a/test/support/fixtures/xdr/claimable_balances.ex +++ b/test/support/fixtures/xdr/claimable_balances.ex @@ -40,7 +40,7 @@ defmodule Stellar.Test.Fixtures.XDR.ClaimableBalances do "00000000929b20b72e5890ab51c24f1cc46fa01c4f318d8d33367d24dd614cfdf5491072" ) do %OperationBody{ - operation: %Operations.ClawbackClaimableBalance{ + value: %Operations.ClawbackClaimableBalance{ balance_id: %ClaimableBalanceID{ claimable_balance_id: %Hash{ value: @@ -61,7 +61,7 @@ defmodule Stellar.Test.Fixtures.XDR.ClaimableBalances do "00000000929b20b72e5890ab51c24f1cc46fa01c4f318d8d33367d24dd614cfdf5491072" ) do %OperationBody{ - operation: %Operations.ClaimClaimableBalance{ + value: %Operations.ClaimClaimableBalance{ balance_id: %ClaimableBalanceID{ claimable_balance_id: %Hash{ value: diff --git a/test/support/fixtures/xdr/ledger.ex b/test/support/fixtures/xdr/ledger.ex index 0cabcf41..13a0a1ea 100644 --- a/test/support/fixtures/xdr/ledger.ex +++ b/test/support/fixtures/xdr/ledger.ex @@ -352,7 +352,7 @@ defmodule Stellar.Test.Fixtures.XDR.Ledger do account_id: "GD726E62G6G4ANHWHIQTH5LNMFVF2EQSEXITB6DZCCTKVU6EQRRE2SJS" ) do %StellarBase.XDR.OperationBody{ - operation: %StellarBase.XDR.Operations.RevokeSponsorship{ + value: %StellarBase.XDR.Operations.RevokeSponsorship{ sponsorship: %StellarBase.XDR.LedgerKey{ entry: %StellarBase.XDR.Account{ account_id: %StellarBase.XDR.AccountID{ @@ -379,7 +379,7 @@ defmodule Stellar.Test.Fixtures.XDR.Ledger do ed25519: "GDAE7O3YJMC7COEZLPJY6OY3P6WGHSHA3QZH2B456JXV4VDEJRAUSA35" ) do %StellarBase.XDR.OperationBody{ - operation: %StellarBase.XDR.Operations.RevokeSponsorship{ + value: %StellarBase.XDR.Operations.RevokeSponsorship{ sponsorship: %StellarBase.XDR.RevokeSponsorshipSigner{ account_id: %StellarBase.XDR.AccountID{ account_id: %StellarBase.XDR.PublicKey{ diff --git a/test/support/fixtures/xdr/liquidity_pools.ex b/test/support/fixtures/xdr/liquidity_pools.ex index 6c5c87e4..0086aef0 100644 --- a/test/support/fixtures/xdr/liquidity_pools.ex +++ b/test/support/fixtures/xdr/liquidity_pools.ex @@ -40,7 +40,7 @@ defmodule Stellar.Test.Fixtures.XDR.LiquidityPools do 10 ) do %OperationBody{ - operation: %Operations.LiquidityPoolWithdraw{ + value: %Operations.LiquidityPoolWithdraw{ amount: %Int64{datum: 1_000_000_000}, min_amount_a: %Int64{datum: 200_000_000}, min_amount_b: %Int64{datum: 100_000_000}, @@ -69,7 +69,7 @@ defmodule Stellar.Test.Fixtures.XDR.LiquidityPools do 2.5 ) do %OperationBody{ - operation: %Operations.LiquidityPoolDeposit{ + value: %Operations.LiquidityPoolDeposit{ max_amount_a: %Int64{datum: 200_000_000}, max_amount_b: %Int64{datum: 100_000_000}, max_price: %Price{ diff --git a/test/support/fixtures/xdr/predicates.ex b/test/support/fixtures/xdr/predicates.ex index f315b7ec..e1a90f65 100644 --- a/test/support/fixtures/xdr/predicates.ex +++ b/test/support/fixtures/xdr/predicates.ex @@ -432,7 +432,7 @@ defmodule Stellar.Test.Fixtures.XDR.Predicates do } ) do %OperationBody{ - operation: %CreateClaimableBalance{ + value: %CreateClaimableBalance{ amount: %Int64{datum: 1_000_000_000}, asset: %Asset{ asset: %AlphaNum4{ diff --git a/test/support/fixtures/xdr/transaction_envelope.ex b/test/support/fixtures/xdr/transaction_envelope.ex index f54f172d..13460251 100644 --- a/test/support/fixtures/xdr/transaction_envelope.ex +++ b/test/support/fixtures/xdr/transaction_envelope.ex @@ -70,7 +70,7 @@ defmodule Stellar.Test.Fixtures.XDR.TransactionEnvelope do source_account: nil }, body: %OperationBody{ - operation: %Operations.CreateAccount{ + value: %Operations.CreateAccount{ destination: %AccountID{ account_id: %PublicKey{ public_key: %UInt256{ @@ -154,7 +154,7 @@ defmodule Stellar.Test.Fixtures.XDR.TransactionEnvelope do source_account: nil }, body: %OperationBody{ - operation: %Operations.CreateAccount{ + value: %Operations.CreateAccount{ destination: %AccountID{ account_id: %PublicKey{ public_key: %UInt256{ diff --git a/test/support/fixtures/xdr/trustline.ex b/test/support/fixtures/xdr/trustline.ex index 6f4758ce..e0cd453f 100644 --- a/test/support/fixtures/xdr/trustline.ex +++ b/test/support/fixtures/xdr/trustline.ex @@ -43,7 +43,7 @@ defmodule Stellar.Test.Fixtures.XDR.Trustline do [] ) do %OperationBody{ - operation: %SetTrustLineFlags{ + value: %SetTrustLineFlags{ asset: %Asset{ asset: %AlphaNum4{ asset_code: %AssetCode4{code: "BTCN", length: 4}, diff --git a/test/support/xdr_fixtures.ex b/test/support/xdr_fixtures.ex index 3656690f..b43a3521 100644 --- a/test/support/xdr_fixtures.ex +++ b/test/support/xdr_fixtures.ex @@ -5,11 +5,12 @@ defmodule Stellar.Test.XDRFixtures do alias Stellar.KeyPair alias Stellar.TxBuild.{ + CreateContractArgs, TransactionSignature, SignerKey, + SorobanAuthorizedInvocation, SourceAccountContractID, - SCAddress, - SCVal + SCVec } alias Stellar.TxBuild.Transaction, as: Tx @@ -20,7 +21,6 @@ defmodule Stellar.Test.XDRFixtures do alias StellarBase.XDR.{ AccountID, - AddressWithNonce, AlphaNum12, AlphaNum4, Asset, @@ -39,9 +39,8 @@ defmodule Stellar.Test.XDRFixtures do Ext, FromAsset, Hash, - HashIDPreimageCreateContractArgs, + HashIDPreimageSorobanAuthorization, HostFunction, - HostFunctionList100, Int32, Int64, Memo, @@ -51,7 +50,7 @@ defmodule Stellar.Test.XDRFixtures do OperationBody, Operation, Operations, - OperationID, + HashIDPreimageOperationID, OptionalAccountID, OptionalDataValue, OptionalMuxedAccount, @@ -66,13 +65,12 @@ defmodule Stellar.Test.XDRFixtures do Signature, SignatureHint, SourceAccountContractID, + SorobanAuthorizationEntryList, String28, String32, String64, StructContractID, Signer, - SCContractExecutable, - SCContractExecutableType, Transaction, TransactionV1Envelope, TransactionEnvelope, @@ -133,16 +131,6 @@ defmodule Stellar.Test.XDRFixtures do |> AccountID.new() end - @spec address_with_nonce_xdr(sc_address :: SCAddress.t(), nonce :: non_neg_integer()) :: - AddressWithNonce.t() - def address_with_nonce_xdr(sc_address, nonce) do - nonce = UInt64.new(nonce) - - sc_address - |> SCAddress.to_xdr() - |> AddressWithNonce.new(nonce) - end - @spec ed25519_contract_id_xdr( network_id :: String.t(), ed25519 :: non_neg_integer(), @@ -169,14 +157,35 @@ defmodule Stellar.Test.XDRFixtures do source_account :: TxAccountID.t(), sequence_number :: TxSequenceNumber.t(), op_num :: non_neg_integer() - ) :: OperationID.t() + ) :: HashIDPreimageOperationID.t() def operation_id_xdr(source_account, sequence_number, op_num) do sequence_number = TxSequenceNumber.to_xdr(sequence_number) op_num = UInt32.new(op_num) source_account |> TxAccountID.to_xdr() - |> OperationID.new(sequence_number, op_num) + |> HashIDPreimageOperationID.new(sequence_number, op_num) + end + + @spec soroban_auth_xdr( + network_id :: String.t(), + nonce :: non_neg_integer(), + signature_expiration_ledger :: non_neg_integer(), + invocation :: SorobanAuthorizedInvocation.t() + ) :: HashIDPreimageSorobanAuthorization.t() + def soroban_auth_xdr( + network_id, + nonce, + signature_expiration_ledger, + invocation + ) do + nonce = Int64.new(nonce) + signature_expiration_ledger = UInt32.new(signature_expiration_ledger) + invocation = SorobanAuthorizedInvocation.to_xdr(invocation) + + network_id + |> Hash.new() + |> HashIDPreimageSorobanAuthorization.new(nonce, signature_expiration_ledger, invocation) end @spec source_account_contract_id_xdr( @@ -207,31 +216,6 @@ defmodule Stellar.Test.XDRFixtures do |> StructContractID.new(contract_id, salt) end - @spec hash_id_preimage_create_contract_args_xdr( - network_id :: binary(), - source :: binary(), - source_type :: String.t(), - salt :: non_neg_integer() - ) :: HashIDPreimageCreateContractArgs.t() - def hash_id_preimage_create_contract_args_xdr(network_id, source, source_type, salt) do - source = sc_contract_executable_xdr(source_type, source) - salt = UInt256.new(salt) - - network_id - |> Hash.new() - |> HashIDPreimageCreateContractArgs.new(source, salt) - end - - @spec sc_contract_executable_xdr(type :: String.t(), value :: binary()) :: - SCContractExecutable.t() - def sc_contract_executable_xdr(type, value) do - type = SCContractExecutableType.new(type) - - value - |> Hash.new() - |> SCContractExecutable.new(type) - end - @spec signer_xdr(key :: String.t(), weight :: non_neg_integer()) :: Signer.t() def signer_xdr(key, weight) do weight = UInt32.new(weight) @@ -328,7 +312,6 @@ defmodule Stellar.Test.XDRFixtures do destination |> muxed_account_xdr() - |> AccountMerge.new() |> OperationBody.new(op_type) end @@ -707,27 +690,28 @@ defmodule Stellar.Test.XDRFixtures do end @spec host_function_xdr( - type :: :invoke, - contract_id :: String.t(), - function_name :: String.t(), - args :: list(SCVal.t()) + type :: :invoke_contract, + args :: SCVec.t() ) :: HostFunction.t() def host_function_xdr( - :invoke, - "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c", - "hello", - [%SCVal{type: :symbol, value: "world"}] + :invoke_contract, + %SCVec{} ) do - %StellarBase.XDR.HostFunctionArgs{ + %StellarBase.XDR.HostFunction{ value: %StellarBase.XDR.SCVec{ - sc_vals: [ + items: [ %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCBytes{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, - 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> + value: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.Hash{ + value: + <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, + 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> + }, + type: %StellarBase.XDR.SCAddressType{ + identifier: :SC_ADDRESS_TYPE_CONTRACT + } }, - type: %StellarBase.XDR.SCValType{identifier: :SCV_BYTES} + type: %StellarBase.XDR.SCValType{identifier: :SCV_ADDRESS} }, %StellarBase.XDR.SCVal{ value: %StellarBase.XDR.SCSymbol{value: "hello"}, @@ -739,194 +723,89 @@ defmodule Stellar.Test.XDRFixtures do } ] }, - type: %StellarBase.XDR.HostFunctionType{identifier: :HOST_FUNCTION_TYPE_INVOKE_CONTRACT} + type: %StellarBase.XDR.HostFunctionType{ + identifier: :HOST_FUNCTION_TYPE_INVOKE_CONTRACT + } } end - @spec host_function_with_auth_xdr( - type :: :invoke, - contract_id :: String.t(), - function_name :: String.t(), - args :: list(SCVal.t()) + @spec host_function_xdr( + type :: :create_contract, + args :: CreateContractArgs.t() ) :: HostFunction.t() - def host_function_with_auth_xdr( - :invoke, - "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c", - "hello", - [%SCVal{type: :symbol, value: "world"}] + def host_function_xdr( + :create_contract, + %CreateContractArgs{} ) do %StellarBase.XDR.HostFunction{ - args: %StellarBase.XDR.HostFunctionArgs{ - value: %StellarBase.XDR.SCVec{ - sc_vals: [ - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCBytes{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, - 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - type: %StellarBase.XDR.SCValType{identifier: :SCV_BYTES} - }, - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCSymbol{value: "hello"}, - type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} - }, - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCSymbol{value: "world"}, - type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} - } - ] - }, - type: %StellarBase.XDR.HostFunctionType{identifier: :HOST_FUNCTION_TYPE_INVOKE_CONTRACT} - }, - auth: %StellarBase.XDR.ContractAuthList{ - auth: [ - %StellarBase.XDR.ContractAuth{ - address_with_nonce: %StellarBase.XDR.OptionalAddressWithNonce{ - address_with_nonce: %StellarBase.XDR.AddressWithNonce{ - address: %StellarBase.XDR.SCAddress{ - sc_address: %StellarBase.XDR.AccountID{ - account_id: %StellarBase.XDR.PublicKey{ - public_key: %StellarBase.XDR.UInt256{ - datum: - <<35, 91, 203, 138, 180, 145, 234, 66, 217, 94, 128, 4, 7, 74, 31, 24, - 11, 155, 95, 195, 137, 228, 19, 220, 153, 243, 25, 2, 64, 172, 119, - 151>> - }, - type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} - } + value: %StellarBase.XDR.CreateContractArgs{ + contract_id_preimage: %StellarBase.XDR.ContractIDPreimage{ + value: %StellarBase.XDR.ContractIDPreimageFromAddress{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<35, 91, 203, 138, 180, 145, 234, 66, 217, 94, 128, 4, 7, 74, 31, 24, 11, + 155, 95, 195, 137, 228, 19, 220, 153, 243, 25, 2, 64, 172, 119, 151>> }, - type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} - }, - nonce: %StellarBase.XDR.UInt64{datum: 123} - } - }, - authorized_invocation: %StellarBase.XDR.AuthorizedInvocation{ - contract_id: %StellarBase.XDR.Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, - 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, - args: %StellarBase.XDR.SCVec{ - sc_vals: [ - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCSymbol{value: "world"}, - type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} - } - ] + type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} + } }, - sub_invocations: %StellarBase.XDR.AuthorizedInvocationList{ - sub_invocations: [ - %StellarBase.XDR.AuthorizedInvocation{ - contract_id: %StellarBase.XDR.Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, - 75, 68, 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, - args: %StellarBase.XDR.SCVec{ - sc_vals: [ - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.SCSymbol{value: "world"}, - type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} - } - ] - }, - sub_invocations: %StellarBase.XDR.AuthorizedInvocationList{ - sub_invocations: [] - } - } - ] - } + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} }, - signature_args: %StellarBase.XDR.SCVec{ - sc_vals: [ - %StellarBase.XDR.SCVal{ - value: %StellarBase.XDR.OptionalSCVec{ - sc_vec: %StellarBase.XDR.SCVec{sc_vals: []} - }, - type: %StellarBase.XDR.SCValType{identifier: :SCV_VEC} - } - ] + salt: %StellarBase.XDR.UInt256{ + datum: + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, + 167, 216, 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> } - } - ] - } - } - end - - @spec host_function_upload_xdr( - type :: :upload, - code :: binary() - ) :: HostFunction.t() - def host_function_upload_xdr(:upload, code) do - %StellarBase.XDR.HostFunctionArgs{ - value: %StellarBase.XDR.UploadContractWasmArgs{ - code: %StellarBase.XDR.VariableOpaque256000{ - opaque: code - } - }, - type: %StellarBase.XDR.HostFunctionType{ - identifier: :HOST_FUNCTION_TYPE_UPLOAD_CONTRACT_WASM - } - } - end - - @spec host_function_create_with_wasm_xdr(type :: atom(), wasm_id :: binary(), salt :: binary()) :: - HostFunction.t() - def host_function_create_with_wasm_xdr(:create, wasm_id, salt) do - %StellarBase.XDR.HostFunctionArgs{ - value: %StellarBase.XDR.CreateContractArgs{ - contract_id: %StellarBase.XDR.ContractID{ - contract_id: %StellarBase.XDR.UInt256{ - datum: salt }, - type: %StellarBase.XDR.ContractIDType{identifier: :CONTRACT_ID_FROM_SOURCE_ACCOUNT} + type: %StellarBase.XDR.ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ADDRESS + } }, - executable: %StellarBase.XDR.SCContractExecutable{ - contract_executable: %StellarBase.XDR.Hash{ - value: wasm_id + executable: %StellarBase.XDR.ContractExecutable{ + value: %StellarBase.XDR.Hash{ + value: + <<86, 32, 6, 9, 172, 4, 212, 185, 249, 87, 184, 164, 58, 34, 167, 183, 226, 117, + 205, 116, 11, 130, 119, 172, 224, 51, 12, 148, 90, 251, 17, 12>> }, - type: %StellarBase.XDR.SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_WASM_REF - } + type: %StellarBase.XDR.ContractExecutableType{identifier: :CONTRACT_EXECUTABLE_WASM} } }, type: %StellarBase.XDR.HostFunctionType{identifier: :HOST_FUNCTION_TYPE_CREATE_CONTRACT} } end - @spec host_function_create_with_asset(type :: atom()) :: HostFunction.t() - def host_function_create_with_asset(:create) do - %StellarBase.XDR.HostFunctionArgs{ - value: %StellarBase.XDR.CreateContractArgs{ - contract_id: %StellarBase.XDR.ContractID{ - contract_id: %StellarBase.XDR.Asset{ - asset: %StellarBase.XDR.Void{value: nil}, - type: %StellarBase.XDR.AssetType{identifier: :ASSET_TYPE_NATIVE} - }, - type: %StellarBase.XDR.ContractIDType{identifier: :CONTRACT_ID_FROM_ASSET} - }, - executable: %StellarBase.XDR.SCContractExecutable{ - contract_executable: %StellarBase.XDR.Void{value: nil}, - type: %StellarBase.XDR.SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_TOKEN - } - } + @spec host_function_xdr( + type :: :upload_contract_wasm, + args :: binary() + ) :: HostFunction.t() + def host_function_xdr( + :upload_contract_wasm, + variable_opaque + ) + when is_binary(variable_opaque) do + %StellarBase.XDR.HostFunction{ + value: %StellarBase.XDR.VariableOpaque{ + opaque: + <<0, 97, 115, 109, 1, 0, 0, 0, 1, 19, 4, 96, 1, 126, 1, 126, 96, 2, 126, 126, 1, 126, + 96, 1, 127, 0, 96, 0, 0, 2, 37, 6, 1, 118, 1, 95, 0, 0, 1, 118, 1, 54, 0, 1, 1, 97, 1, + 48, 0, 0, 1, 108, 1, 48, 0, 0>> }, - type: %StellarBase.XDR.HostFunctionType{identifier: :HOST_FUNCTION_TYPE_CREATE_CONTRACT} + type: %StellarBase.XDR.HostFunctionType{ + identifier: :HOST_FUNCTION_TYPE_UPLOAD_CONTRACT_WASM + } } end - @spec invoke_host_function_op_xdr(functions :: list(TxHostFunction.t())) :: OperationBody.t() - def invoke_host_function_op_xdr(functions) do + @spec invoke_host_function_op_xdr(function :: TxHostFunction.t()) :: OperationBody.t() + def invoke_host_function_op_xdr(function) do op_type = OperationType.new(:INVOKE_HOST_FUNCTION) - functions - |> Enum.map(&TxHostFunction.to_xdr/1) - |> HostFunctionList100.new() - |> InvokeHostFunction.new() + function + |> TxHostFunction.to_xdr() + |> InvokeHostFunction.new(SorobanAuthorizationEntryList.new([])) |> OperationBody.new(op_type) end diff --git a/test/tx_build/address_with_nonce_test.exs b/test/tx_build/address_with_nonce_test.exs deleted file mode 100644 index 3c94bf9b..00000000 --- a/test/tx_build/address_with_nonce_test.exs +++ /dev/null @@ -1,38 +0,0 @@ -defmodule Stellar.TxBuild.AddressWithNonceTest do - use ExUnit.Case - - import Stellar.Test.XDRFixtures, only: [address_with_nonce_xdr: 2] - - alias Stellar.TxBuild.AddressWithNonce, as: TxAddressWithNonce - alias Stellar.TxBuild.SCAddress, as: TxSCAddress - - setup do - address = TxSCAddress.new("GB6FIXFOEK46VBDAG5USXRKKDJYFOBQZDMAPOYY6MC4KMRTSPVUH3X2A") - nonce = 123 - xdr = address_with_nonce_xdr(address, nonce) - - %{address: address, nonce: nonce, xdr: xdr} - end - - test "new/1", %{address: address, nonce: nonce} do - %TxAddressWithNonce{ - address: ^address, - nonce: ^nonce - } = TxAddressWithNonce.new(address: address, nonce: nonce) - end - - test "new/1 with invalid args" do - {:error, :invalid_address_with_nonce} = TxAddressWithNonce.new("invalid_args") - end - - test "to_xdr/1", - %{address: address, nonce: nonce, xdr: xdr} do - ^xdr = - TxAddressWithNonce.new(address: address, nonce: nonce) - |> TxAddressWithNonce.to_xdr() - end - - test "to_xdr/1 with invalid struct" do - {:error, :invalid_struct_address_with_nonce} = TxAddressWithNonce.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/authorized_invocation_test.exs b/test/tx_build/authorized_invocation_test.exs deleted file mode 100644 index 5c6a051f..00000000 --- a/test/tx_build/authorized_invocation_test.exs +++ /dev/null @@ -1,135 +0,0 @@ -defmodule Stellar.TxBuild.AuthorizedInvocationTest do - use ExUnit.Case - - alias Stellar.TxBuild.AuthorizedInvocation, as: TxAuthorizedInvocation - alias Stellar.TxBuild.SCVal, as: TxSCVal - - alias StellarBase.XDR.{ - AuthorizedInvocation, - AuthorizedInvocationList, - Hash, - Int32, - SCSymbol, - SCVal, - SCValType, - SCVec - } - - setup do - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "function_name" - - sc_val = TxSCVal.new(i32: 123) - args = [sc_val] - - authorized_invocation = TxAuthorizedInvocation.new([contract_id, function_name, args, []]) - - %{ - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [authorized_invocation] - } - end - - test "new/1 without sub_invocations", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - %TxAuthorizedInvocation{ - contract_id: ^contract_id, - function_name: ^function_name, - args: ^args, - sub_invocations: [] - } = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) - end - - test "new/1 with sub_invocations", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - %TxAuthorizedInvocation{} = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) - end - - test "new/1 with invalid args" do - {:error, :invalid_authorized_invocation} = TxAuthorizedInvocation.new("invalid_args") - end - - test "new/1 with invalid sub_invocations value", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - {:error, :invalid_sub_invocations} = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: "invalid_value" - ) - end - - test "new/1 with invalid sub_invocations list", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - {:error, :invalid_sub_invocations} = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [1, 2, 3, 4] - ) - end - - test "to_xdr/1", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - %AuthorizedInvocation{ - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, 84, - 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "function_name"}, - args: %SCVec{ - sc_vals: [ - %SCVal{ - value: %Int32{datum: 123}, - type: %SCValType{identifier: :SCV_I32} - } - ] - }, - sub_invocations: %AuthorizedInvocationList{sub_invocations: []} - } = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) - |> TxAuthorizedInvocation.to_xdr() - end - - test "to_xdr/1 when the struct is invalid" do - {:error, :invalid_struct_authorized_invocation} = - TxAuthorizedInvocation.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/contract_auth_test.exs b/test/tx_build/contract_auth_test.exs deleted file mode 100644 index dfe739bf..00000000 --- a/test/tx_build/contract_auth_test.exs +++ /dev/null @@ -1,307 +0,0 @@ -defmodule Stellar.TxBuild.ContractAuthTest do - use ExUnit.Case - - alias Stellar.TxBuild.ContractAuth, as: TxContractAuth - alias Stellar.TxBuild.AddressWithNonce, as: TxAddressWithNonce - alias Stellar.TxBuild.OptionalAddressWithNonce, as: TxOptionalAddressWithNonce - alias Stellar.TxBuild.AuthorizedInvocation, as: TxAuthorizedInvocation - alias Stellar.TxBuild.SCVal, as: TxSCVal - alias Stellar.TxBuild.SCAddress, as: TxSCAddress - - alias StellarBase.XDR.{ - AccountID, - AddressWithNonce, - AuthorizedInvocation, - AuthorizedInvocationList, - ContractAuth, - Hash, - Int32, - OptionalAddressWithNonce, - OptionalSCVec, - PublicKey, - PublicKeyType, - SCAddress, - SCAddressType, - SCVec, - SCVal, - SCValType, - SCSymbol, - UInt64, - UInt256 - } - - setup do - # ADDRESS WITH NONCE - sc_address = TxSCAddress.new("GB6FIXFOEK46VBDAG5USXRKKDJYFOBQZDMAPOYY6MC4KMRTSPVUH3X2A") - - address_with_nonce = TxAddressWithNonce.new(address: sc_address, nonce: 123) - optional_address_with_nonce = TxOptionalAddressWithNonce.new(address_with_nonce) - - # AUTHORIZED INVOCATION - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "hello" - args = [TxSCVal.new(i32: 321)] - - authorized_invocation_1 = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - sub_invocations: [], - args: args - ) - - authorized_invocation_2 = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - sub_invocations: [authorized_invocation_1], - args: args - ) - - # SCVAL - signature_args = [TxSCVal.new(i32: 456)] - - secret_key = "SCAVFA3PI3MJLTQNMXOUNBSEUOSY66YMG3T2KCQKLQBENNVLVKNPV3EK" - - base_64_without_sign = - "AAAAAQAAAAAAAAAAyU545WHCcUig2re/I2xMg5FaqNroaTV+AXQbahq8ftYAAAAAAAAABL5BOLMcxdDZ2RtTGT10MW0lRAZ5TsD4HT7UD03BuGpuAAAABHN3YXAAAAACAAAACgAAAAAAAABkAAAAAAAAAAAAAAAKAAAAAAAAE4gAAAAAAAAAAAAAAAAAAAAA" - - base_64_string = - "AAAAAQAAAAAAAAAAyU545WHCcUig2re/I2xMg5FaqNroaTV+AXQbahq8ftYAAAAAAAAABL5BOLMcxdDZ2RtTGT10MW0lRAZ5TsD4HT7UD03BuGpuAAAABHN3YXAAAAACAAAACgAAAAAAAABkAAAAAAAAAAAAAAAKAAAAAAAAE4gAAAAAAAAAAAAAAAAAAAABAAAAEAAAAAEAAAABAAAAEQAAAAEAAAACAAAADwAAAApwdWJsaWNfa2V5AAAAAAANAAAAIMlOeOVhwnFIoNq3vyNsTIORWqja6Gk1fgF0G2oavH7WAAAADwAAAAlzaWduYXR1cmUAAAAAAAANAAAAQJUdF06WSRhT4dI1W4OhVEyjN3lOCTIFcLDmF+F1d4tc+g1e9sRmjDuz14tj+wXE3VeJxgn+94B92A6fZmeZEgI=" - - %{ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args, - optional_address_with_nonce: optional_address_with_nonce, - secret_key: secret_key, - base_64_string: base_64_string, - base_64_without_sign: base_64_without_sign - } - end - - test "new/1", %{ - address_with_nonce: address_with_nonce, - optional_address_with_nonce: optional_address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - } do - %TxContractAuth{ - address_with_nonce: ^optional_address_with_nonce, - authorized_invocation: ^authorized_invocation_2, - signature_args: ^signature_args - } = - TxContractAuth.new( - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - ) - end - - test "new/1 with invalid args" do - {:error, :invalid_contract_auth} = TxContractAuth.new("invalid_args") - end - - test "new/1 with invalid authorized_invocation", %{ - address_with_nonce: address_with_nonce, - signature_args: signature_args - } do - {:error, :invalid_authorized_invocation} = - TxContractAuth.new( - address_with_nonce: address_with_nonce, - authorized_invocation: "invalid", - signature_args: signature_args - ) - end - - test "to_xdr/1", %{ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - } do - %ContractAuth{ - address_with_nonce: %OptionalAddressWithNonce{ - address_with_nonce: %AddressWithNonce{ - address: %SCAddress{ - sc_address: %AccountID{ - account_id: %PublicKey{ - public_key: %UInt256{ - datum: - <<124, 84, 92, 174, 34, 185, 234, 132, 96, 55, 105, 43, 197, 74, 26, 112, 87, - 6, 25, 27, 0, 247, 99, 30, 96, 184, 166, 70, 114, 125, 104, 125>> - }, - type: %PublicKeyType{ - identifier: :PUBLIC_KEY_TYPE_ED25519 - } - } - }, - type: %SCAddressType{ - identifier: :SC_ADDRESS_TYPE_ACCOUNT - } - }, - nonce: %UInt64{datum: 123} - } - }, - authorized_invocation: %AuthorizedInvocation{ - args: %SCVec{ - sc_vals: [ - %SCVal{ - type: %SCValType{identifier: :SCV_I32}, - value: %Int32{datum: 321} - } - ] - }, - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, 84, - 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "hello"}, - sub_invocations: %AuthorizedInvocationList{ - sub_invocations: [ - %AuthorizedInvocation{ - args: %SCVec{ - sc_vals: [ - %SCVal{ - type: %SCValType{identifier: :SCV_I32}, - value: %Int32{datum: 321} - } - ] - }, - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, - 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "hello"}, - sub_invocations: %AuthorizedInvocationList{ - sub_invocations: [] - } - } - ] - } - }, - signature_args: %SCVec{ - sc_vals: [ - %SCVal{ - type: %SCValType{identifier: :SCV_VEC}, - value: %OptionalSCVec{ - sc_vec: %SCVec{ - sc_vals: [ - %SCVal{ - type: %SCValType{identifier: :SCV_I32}, - value: %Int32{datum: 456} - } - ] - } - } - } - ] - } - } = - [ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - ] - |> TxContractAuth.new() - |> TxContractAuth.to_xdr() - end - - test "sign/2", %{ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - } do - contract_auth = - TxContractAuth.new( - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - ) - - %Stellar.TxBuild.ContractAuth{ - address_with_nonce: %Stellar.TxBuild.OptionalAddressWithNonce{ - address_with_nonce: %Stellar.TxBuild.AddressWithNonce{ - address: %Stellar.TxBuild.SCAddress{ - type: :account, - value: "GB6FIXFOEK46VBDAG5USXRKKDJYFOBQZDMAPOYY6MC4KMRTSPVUH3X2A" - }, - nonce: 123 - } - }, - authorized_invocation: %Stellar.TxBuild.AuthorizedInvocation{ - contract_id: "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c", - function_name: "hello", - args: [%Stellar.TxBuild.SCVal{type: :i32, value: 321}], - sub_invocations: [ - %Stellar.TxBuild.AuthorizedInvocation{ - contract_id: "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c", - function_name: "hello", - args: [%Stellar.TxBuild.SCVal{type: :i32, value: 321}], - sub_invocations: [] - } - ] - }, - signature_args: [ - %Stellar.TxBuild.SCVal{type: :i32, value: 456}, - %Stellar.TxBuild.SCVal{ - type: :map, - value: [ - %Stellar.TxBuild.SCMapEntry{ - key: %Stellar.TxBuild.SCVal{type: :symbol, value: "public_key"}, - val: %Stellar.TxBuild.SCVal{ - type: :bytes, - value: - <<90, 59, 33, 159, 27, 241, 148, 234, 43, 78, 208, 73, 92, 40, 119, 5, 169, 84, - 190, 125, 179, 121, 108, 107, 112, 211, 32, 194, 193, 98, 177, 218>> - } - }, - %Stellar.TxBuild.SCMapEntry{ - key: %Stellar.TxBuild.SCVal{type: :symbol, value: "signature"}, - val: %Stellar.TxBuild.SCVal{ - type: :bytes, - value: - <<70, 0, 69, 48, 162, 145, 42, 247, 159, 79, 173, 195, 194, 115, 212, 186, 218, - 171, 113, 111, 0, 136, 135, 161, 252, 135, 105, 217, 69, 85, 196, 95, 223, - 168, 95, 103, 122, 132, 220, 26, 84, 216, 10, 6, 123, 204, 218, 216, 102, 166, - 159, 111, 129, 17, 233, 40, 245, 237, 184, 223, 158, 0, 41, 10>> - } - } - ] - } - ] - } = - TxContractAuth.sign( - contract_auth, - "SDRD4CSRGPWUIPRDS5O3CJBNJME5XVGWNI677MZDD4OD2ZL2R6K5IQ24" - ) - end - - test "sign/2 with invalid secret key", %{ - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - } do - contract_auth = - TxContractAuth.new( - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - signature_args: signature_args - ) - - {:error, :invalid_secret_key} = TxContractAuth.sign(contract_auth, 123) - end - - test "to_xdr/1 when the struct is invalid" do - {:error, :invalid_struct_contract_auth} = TxContractAuth.to_xdr("invalid_struct") - end - - test "sign_xdr/2", %{ - base_64_without_sign: base_64_without_sign, - base_64_string: base_64_string, - secret_key: secret_key - } do - ^base_64_string = TxContractAuth.sign_xdr(base_64_without_sign, secret_key) - end -end diff --git a/test/tx_build/contract_executable_test.exs b/test/tx_build/contract_executable_test.exs new file mode 100644 index 00000000..4623ba9c --- /dev/null +++ b/test/tx_build/contract_executable_test.exs @@ -0,0 +1,58 @@ +defmodule Stellar.TxBuild.ContractExecutableTest do + use ExUnit.Case + + alias Stellar.TxBuild.ContractExecutable, as: TxContractExecutable + alias StellarBase.XDR.{ContractExecutable, ContractExecutableType, Hash, Void} + + setup do + %{ + hash: "example" + } + end + + test "new/1 when type is wasm_ref", %{hash: hash} do + %TxContractExecutable{ + type: :wasm_ref, + value: ^hash + } = TxContractExecutable.new(wasm_ref: hash) + end + + test "new/1 when type is token" do + %TxContractExecutable{ + type: :token, + value: nil + } = TxContractExecutable.new(:token) + end + + test "new/1 with invalid type", %{hash: hash} do + {:error, :invalid_contract_executable} = TxContractExecutable.new(any: hash) + end + + test "new/1 with invalid args" do + {:error, :invalid_contract_executable} = TxContractExecutable.new("invalid_args") + end + + test "new/1 with wasm invalid hash" do + {:error, :invalid_contract_executable} = TxContractExecutable.new(wasm_ref: 123) + end + + test "to_xdr/1 with wasm_ref type", %{hash: hash} do + %ContractExecutable{ + value: %Hash{value: ^hash}, + type: %ContractExecutableType{ + identifier: :CONTRACT_EXECUTABLE_WASM + } + } = TxContractExecutable.new(wasm_ref: hash) |> TxContractExecutable.to_xdr() + end + + test "to_xdr/1 with token type" do + %ContractExecutable{ + value: %Void{value: nil}, + type: %ContractExecutableType{identifier: :CONTRACT_EXECUTABLE_TOKEN} + } = TxContractExecutable.new(:token) |> TxContractExecutable.to_xdr() + end + + test "to_xdr/1 with invalid struct" do + {:error, :invalid_struct} = TxContractExecutable.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/contract_id_preimage_from_address_test.exs b/test/tx_build/contract_id_preimage_from_address_test.exs new file mode 100644 index 00000000..4cd3a25d --- /dev/null +++ b/test/tx_build/contract_id_preimage_from_address_test.exs @@ -0,0 +1,60 @@ +defmodule Stellar.TxBuild.ContractIDPreimageFromAddressTest do + use ExUnit.Case + + alias Stellar.TxBuild.{SCAddress, ContractIDPreimageFromAddress} + alias StellarBase.XDR.ContractIDPreimageFromAddress, as: ContractIDPreimageFromAddressXDR + + setup do + salt = + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, 216, + 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + + address = SCAddress.new("GDZ6PM5NEFJTCKPGKXV5KCJ7RYQNPWYUB2RCBIXDYULPX2B7UW54IVN7") + + %{ + salt: salt, + address: address + } + end + + test "new/1", %{salt: salt, address: address} do + %ContractIDPreimageFromAddress{ + address: ^address, + salt: ^salt + } = ContractIDPreimageFromAddress.new([{:address, address}, {:salt, salt}]) + end + + test "new/1 with invalid values" do + {:error, :invalid_contract_id_preimage_value} = + ContractIDPreimageFromAddress.new([{:address, "invalid"}, {:salt, 1234}]) + end + + test "to_xdr/1", %{salt: salt, address: address} do + %ContractIDPreimageFromAddressXDR{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<243, 231, 179, 173, 33, 83, 49, 41, 230, 85, 235, 213, 9, 63, 142, 32, 215, 219, + 20, 14, 162, 32, 162, 227, 197, 22, 251, 232, 63, 165, 187, 196>> + }, + type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} + } + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} + }, + salt: %StellarBase.XDR.UInt256{ + datum: + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, + 216, 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + } + } = + ContractIDPreimageFromAddress.new([{:address, address}, {:salt, salt}]) + |> ContractIDPreimageFromAddress.to_xdr() + end + + test "to_xdr/1 with the struct is invalid" do + {:error, :invalid_struct} = ContractIDPreimageFromAddress.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/contract_id_preimage_test.exs b/test/tx_build/contract_id_preimage_test.exs new file mode 100644 index 00000000..664dd85e --- /dev/null +++ b/test/tx_build/contract_id_preimage_test.exs @@ -0,0 +1,104 @@ +defmodule Stellar.TxBuild.ContractIDPreimageTest do + use ExUnit.Case + + alias Stellar.TxBuild.{Asset, SCAddress, ContractIDPreimage, ContractIDPreimageFromAddress} + alias StellarBase.XDR.ContractIDPreimage, as: ContractIDPreimageXDR + + setup do + salt = + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, 216, + 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + + address = SCAddress.new("GDZ6PM5NEFJTCKPGKXV5KCJ7RYQNPWYUB2RCBIXDYULPX2B7UW54IVN7") + + contract_id_preimage_from_address = + ContractIDPreimageFromAddress.new([{:address, address}, {:salt, salt}]) + + asset = Asset.new(:native) + + %{ + asset: asset, + contract_id_preimage_from_address: contract_id_preimage_from_address + } + end + + test "new/1 when type is from_address", %{ + contract_id_preimage_from_address: contract_id_preimage_from_address + } do + %ContractIDPreimage{ + type: :from_address, + value: ^contract_id_preimage_from_address + } = ContractIDPreimage.new(from_address: contract_id_preimage_from_address) + end + + test "new/1 when type is from_asset", %{asset: asset} do + %ContractIDPreimage{ + type: :from_asset, + value: ^asset + } = ContractIDPreimage.new(from_asset: asset) + end + + test "new/1 with invalid type", %{asset: asset} do + {:error, :invalid_contract_id_preimage} = ContractIDPreimage.new(any: asset) + end + + test "new/1 with invalid args" do + {:error, :invalid_contract_id_preimage} = ContractIDPreimage.new("invalid_args") + end + + test "new/1 with invalid ContractIDPreimageFromAddress" do + {:error, :invalid_from_address} = ContractIDPreimage.new(from_address: "invalid") + end + + test "new/1 with invalid Asset" do + {:error, :invalid_from_asset} = ContractIDPreimage.new(from_asset: "invalid") + end + + test "to_xdr/1 with from_address type", %{ + contract_id_preimage_from_address: contract_id_preimage_from_address + } do + %ContractIDPreimageXDR{ + value: %StellarBase.XDR.ContractIDPreimageFromAddress{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<243, 231, 179, 173, 33, 83, 49, 41, 230, 85, 235, 213, 9, 63, 142, 32, 215, + 219, 20, 14, 162, 32, 162, 227, 197, 22, 251, 232, 63, 165, 187, 196>> + }, + type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} + } + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} + }, + salt: %StellarBase.XDR.UInt256{ + datum: + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, + 216, 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + } + }, + type: %StellarBase.XDR.ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ADDRESS + } + } = + ContractIDPreimage.new(from_address: contract_id_preimage_from_address) + |> ContractIDPreimage.to_xdr() + end + + test "to_xdr/1 with asset type", %{asset: asset} do + %ContractIDPreimageXDR{ + value: %StellarBase.XDR.Asset{ + asset: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.AssetType{identifier: :ASSET_TYPE_NATIVE} + }, + type: %StellarBase.XDR.ContractIDPreimageType{identifier: :CONTRACT_ID_PREIMAGE_FROM_ASSET} + } = + ContractIDPreimage.new(from_asset: asset) + |> ContractIDPreimage.to_xdr() + end + + test "to_xdr/1 with the struct is invalid" do + {:error, :invalid_struct} = ContractIDPreimage.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/create_contract_args_test.exs b/test/tx_build/create_contract_args_test.exs new file mode 100644 index 00000000..3f5f1863 --- /dev/null +++ b/test/tx_build/create_contract_args_test.exs @@ -0,0 +1,84 @@ +defmodule Stellar.TxBuild.CreateContractArgsTest do + use ExUnit.Case + + alias Stellar.TxBuild.{ + Asset, + CreateContractArgs, + ContractIDPreimage, + ContractExecutable + } + + alias StellarBase.XDR.CreateContractArgs, as: CreateContractArgsXDR + + setup do + asset = Asset.new(:native) + contract_executable = ContractExecutable.new(:token) + contract_id_preimage = ContractIDPreimage.new(from_asset: asset) + + %{ + asset: asset, + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + } + end + + test "new/1", %{ + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + } do + %CreateContractArgs{ + contract_id_preimage: ^contract_id_preimage, + contract_executable: ^contract_executable + } = + CreateContractArgs.new( + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + ) + end + + test "new/1 with invalid ContractIDPreimage", %{contract_executable: contract_executable} do + {:error, :invalid_contract_id_preimage} = + CreateContractArgs.new( + contract_id_preimage: "invalid", + contract_executable: contract_executable + ) + end + + test "new/1 with invalid ContractExecutable", %{contract_id_preimage: contract_id_preimage} do + {:error, :invalid_contract_executable} = + CreateContractArgs.new( + contract_executable: "invalid", + contract_id_preimage: contract_id_preimage + ) + end + + test "to_xdr/1", %{ + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + } do + %CreateContractArgsXDR{ + contract_id_preimage: %StellarBase.XDR.ContractIDPreimage{ + value: %StellarBase.XDR.Asset{ + asset: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.AssetType{identifier: :ASSET_TYPE_NATIVE} + }, + type: %StellarBase.XDR.ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ASSET + } + }, + executable: %StellarBase.XDR.ContractExecutable{ + value: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.ContractExecutableType{identifier: :CONTRACT_EXECUTABLE_TOKEN} + } + } = + CreateContractArgs.new( + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + ) + |> CreateContractArgs.to_xdr() + end + + test "to_xdr/1 with the struct is invalid" do + {:error, :invalid_struct} = CreateContractArgs.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/default_test.exs b/test/tx_build/default_test.exs index 155b9299..76f18f0d 100644 --- a/test/tx_build/default_test.exs +++ b/test/tx_build/default_test.exs @@ -333,7 +333,7 @@ defmodule Stellar.TxBuild.DefaultTest do test "set_soroban_data/2", %{tx_build: tx_build} do soroban_data = - "AAAAAgAAAAZQma4vqEU8Njqacc34GYyiWNEvpEu13GiuAiVZX0YdNwAAABQAAAAHRhmB7Imi4CwJhmzp1r/d76UShPJrO5PSHOV2Z9tPbE8AAAAAABJ8KwAAE3AAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + "AAAAAAAAAAEAAAAHmDXys1KuBimD87u2AiUG/jb5CqOkQW/qASpb6gMVRlsAAAAAAAAAAQAAAAYAAAABZ+A/h5d/0pJnw7wmIzptCvWoX0md87QkHN68pAOfYjgAAAAUAAAAAQAAAAAANwsUAAAUmAAAAQQAAAMcAAAAAAAAAJw=" {soroban_xdr_data, ""} = soroban_data |> Base.decode64!() |> SorobanTransactionData.decode_xdr!() @@ -352,7 +352,7 @@ defmodule Stellar.TxBuild.DefaultTest do test "set_soroban_data/2 piping_error" do soroban_data = - "AAAAAgAAAAZQma4vqEU8Njqacc34GYyiWNEvpEu13GiuAiVZX0YdNwAAABQAAAAHRhmB7Imi4CwJhmzp1r/d76UShPJrO5PSHOV2Z9tPbE8AAAAAABJ8KwAAE3AAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + "AAAAAAAAAAEAAAAHmDXys1KuBimD87u2AiUG/jb5CqOkQW/qASpb6gMVRlsAAAAAAAAAAQAAAAYAAAABZ+A/h5d/0pJnw7wmIzptCvWoX0md87QkHN68pAOfYjgAAAAUAAAAAQAAAAAANwsUAAAUmAAAAQQAAAMcAAAAAAAAAJw=" {soroban_xdr_data, ""} = soroban_data |> Base.decode64!() |> SorobanTransactionData.decode_xdr!() diff --git a/test/tx_build/hash_id_preimage_contract_auth_test.exs b/test/tx_build/hash_id_preimage_contract_auth_test.exs deleted file mode 100644 index 240aa879..00000000 --- a/test/tx_build/hash_id_preimage_contract_auth_test.exs +++ /dev/null @@ -1,138 +0,0 @@ -defmodule Stellar.TxBuild.HashIDPreimageContractAuthTest do - use ExUnit.Case - - alias Stellar.TxBuild.HashIDPreimageContractAuth, as: TxHashIDPreimageContractAuth - alias Stellar.TxBuild.AuthorizedInvocation, as: TxAuthorizedInvocation - alias Stellar.TxBuild.SCVal, as: TxSCVal - - alias StellarBase.XDR.{ - AuthorizedInvocation, - AuthorizedInvocationList, - HashIDPreimageContractAuth, - Hash, - Int32, - SCSymbol, - SCVal, - SCVec, - SCValType, - UInt64 - } - - setup do - # SCVAL - sc_val = TxSCVal.new(i32: 123) - - # AUTHORIZED INVOCATION - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "function_name" - args = [sc_val] - - authorized_invocation_1 = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) - - authorized_invocation_2 = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [authorized_invocation_1] - ) - - %{ - network_id: "network_id", - nonce: 123, - invocation: authorized_invocation_2 - } - end - - test "new/1", %{network_id: network_id, nonce: nonce, invocation: invocation} do - %TxHashIDPreimageContractAuth{ - network_id: ^network_id, - nonce: ^nonce, - invocation: ^invocation - } = - TxHashIDPreimageContractAuth.new( - network_id: network_id, - nonce: nonce, - invocation: invocation - ) - end - - test "new/1 with invalid args" do - {:error, :invalid_hash_id_preimage_contract_auth} = - TxHashIDPreimageContractAuth.new("invalid_args") - end - - test "new/1 with invalid authorized invocation", %{network_id: network_id, nonce: nonce} do - {:error, :invalid_invocation} = - TxHashIDPreimageContractAuth.new( - network_id: network_id, - nonce: nonce, - invocation: "invalid_value" - ) - end - - test "to_xdr/1", %{ - network_id: network_id, - nonce: nonce, - invocation: invocation - } do - %HashIDPreimageContractAuth{ - network_id: %Hash{value: "network_id"}, - nonce: %UInt64{datum: 123}, - invocation: %AuthorizedInvocation{ - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, 84, - 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "function_name"}, - args: %SCVec{ - sc_vals: [ - %SCVal{ - value: %Int32{datum: 123}, - type: %SCValType{identifier: :SCV_I32} - } - ] - }, - sub_invocations: %AuthorizedInvocationList{ - sub_invocations: [ - %AuthorizedInvocation{ - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, - 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "function_name"}, - args: %SCVec{ - sc_vals: [ - %SCVal{ - value: %Int32{datum: 123}, - type: %SCValType{identifier: :SCV_I32} - } - ] - }, - sub_invocations: %AuthorizedInvocationList{sub_invocations: []} - } - ] - } - } - } = - TxHashIDPreimageContractAuth.new( - network_id: network_id, - nonce: nonce, - invocation: invocation - ) - |> TxHashIDPreimageContractAuth.to_xdr() - end - - test "to_xdr/1 when the struct is invalid" do - {:error, :invalid_struct_hash_id_preimage_contract_auth} = - TxHashIDPreimageContractAuth.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/hash_id_preimage_contract_id_test.exs b/test/tx_build/hash_id_preimage_contract_id_test.exs new file mode 100644 index 00000000..9e5069c0 --- /dev/null +++ b/test/tx_build/hash_id_preimage_contract_id_test.exs @@ -0,0 +1,79 @@ +defmodule Stellar.TxBuild.HashIDPreimageContractIDTest do + use ExUnit.Case + + alias Stellar.TxBuild.{ + Asset, + HashIDPreimageContractID, + ContractIDPreimage + } + + setup do + network_id = "network" + asset = Asset.new(:native) + contract_id_preimage = ContractIDPreimage.new(from_asset: asset) + + %{ + network_id: network_id, + contract_id_preimage: contract_id_preimage + } + end + + test "new/1", %{ + contract_id_preimage: contract_id_preimage, + network_id: network_id + } do + %HashIDPreimageContractID{ + contract_id_preimage: ^contract_id_preimage, + network_id: ^network_id + } = + HashIDPreimageContractID.new( + network_id: network_id, + contract_id_preimage: contract_id_preimage + ) + end + + test "new/1 with invalid args" do + {:error, :invalid_hash_id_preimage_contract_id} = + HashIDPreimageContractID.new( + network_id: 1234, + contract_id_preimage: "invalid" + ) + end + + test "new/1 with invalid ContractIDPreimage", %{ + network_id: network_id + } do + {:error, :invalid_contract_id_preimage} = + HashIDPreimageContractID.new( + network_id: network_id, + contract_id_preimage: "invalid" + ) + end + + test "to_xdr/1", %{ + contract_id_preimage: contract_id_preimage, + network_id: network_id + } do + %StellarBase.XDR.HashIDPreimageContractID{ + network_id: %StellarBase.XDR.Hash{value: "network"}, + contract_id_preimage: %StellarBase.XDR.ContractIDPreimage{ + value: %StellarBase.XDR.Asset{ + asset: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.AssetType{identifier: :ASSET_TYPE_NATIVE} + }, + type: %StellarBase.XDR.ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ASSET + } + } + } = + HashIDPreimageContractID.new( + network_id: network_id, + contract_id_preimage: contract_id_preimage + ) + |> HashIDPreimageContractID.to_xdr() + end + + test "to_xdr/1 with the struct is invalid" do + {:error, :invalid_struct} = HashIDPreimageContractID.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/hash_id_preimage_create_contract_args_test.exs b/test/tx_build/hash_id_preimage_create_contract_args_test.exs deleted file mode 100644 index 3d5dffe6..00000000 --- a/test/tx_build/hash_id_preimage_create_contract_args_test.exs +++ /dev/null @@ -1,63 +0,0 @@ -defmodule Stellar.TxBuild.HashIDPreimageCreateContractArgsTest do - use ExUnit.Case - - import Stellar.Test.XDRFixtures, only: [hash_id_preimage_create_contract_args_xdr: 4] - - alias Stellar.TxBuild.HashIDPreimageCreateContractArgs, as: TxHashIDPreimageCreateContractArgs - alias Stellar.TxBuild.SCContractExecutable, as: TxSCContractExecutable - - setup do - network_id = "network_id" - executable = "sc_contract_executable" - executable_type = :SCCONTRACT_EXECUTABLE_WASM_REF - salt = 123 - - xdr = hash_id_preimage_create_contract_args_xdr(network_id, executable, executable_type, salt) - - %{ - network_id: network_id, - executable: TxSCContractExecutable.new(wasm_ref: "sc_contract_executable"), - salt: salt, - xdr: xdr - } - end - - test "new/1", %{network_id: network_id, executable: executable, salt: salt} do - %TxHashIDPreimageCreateContractArgs{ - network_id: ^network_id, - executable: ^executable, - salt: ^salt - } = - TxHashIDPreimageCreateContractArgs.new( - network_id: network_id, - executable: executable, - salt: salt - ) - end - - test "new/1 with invalid args" do - {:error, :invalid_hash_id_preimage_contract_args} = - TxHashIDPreimageCreateContractArgs.new("invalid_args") - end - - test "new/1 with invalid executable", %{network_id: network_id, salt: salt} do - {:error, :invalid_executable} = - TxHashIDPreimageCreateContractArgs.new( - network_id: network_id, - executable: "invalid_value", - salt: salt - ) - end - - test "to_xdr/1", %{network_id: network_id, executable: executable, salt: salt, xdr: xdr} do - ^xdr = - [network_id: network_id, executable: executable, salt: salt] - |> TxHashIDPreimageCreateContractArgs.new() - |> TxHashIDPreimageCreateContractArgs.to_xdr() - end - - test "to_xdr/1 when the struct is invalid" do - {:error, :invalid_struct_hash_id_preimage_contract_args} = - TxHashIDPreimageCreateContractArgs.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/operation_id_test.exs b/test/tx_build/hash_id_preimage_operation_id_test.exs similarity index 92% rename from test/tx_build/operation_id_test.exs rename to test/tx_build/hash_id_preimage_operation_id_test.exs index da2957ef..daab2d4a 100644 --- a/test/tx_build/operation_id_test.exs +++ b/test/tx_build/hash_id_preimage_operation_id_test.exs @@ -1,9 +1,9 @@ -defmodule Stellar.TxBuild.OperationIDTest do +defmodule Stellar.TxBuild.HashIDPreimageOperationIDTest do use ExUnit.Case import Stellar.Test.XDRFixtures, only: [operation_id_xdr: 3] - alias Stellar.TxBuild.OperationID, as: TxOperationID + alias Stellar.TxBuild.HashIDPreimageOperationID, as: TxOperationID alias Stellar.TxBuild.AccountID, as: TxAccountID alias Stellar.TxBuild.SequenceNumber, as: TxSequenceNumber diff --git a/test/tx_build/revoke_id_test.exs b/test/tx_build/hash_id_preimage_revoke_id_test.exs similarity index 92% rename from test/tx_build/revoke_id_test.exs rename to test/tx_build/hash_id_preimage_revoke_id_test.exs index 712e1170..ce393818 100644 --- a/test/tx_build/revoke_id_test.exs +++ b/test/tx_build/hash_id_preimage_revoke_id_test.exs @@ -1,7 +1,7 @@ -defmodule Stellar.TxBuild.RevokeIDTest do +defmodule Stellar.TxBuild.HashIDPreimageRevokeIDTest do use ExUnit.Case - alias Stellar.TxBuild.RevokeID, as: TxRevokeID + alias Stellar.TxBuild.HashIDPreimageRevokeID, as: TxRevokeID alias Stellar.TxBuild.SequenceNumber, as: TxSequenceNumber alias Stellar.TxBuild.PoolID, as: TxPoolID alias Stellar.TxBuild.Asset, as: TxAsset @@ -14,7 +14,7 @@ defmodule Stellar.TxBuild.RevokeIDTest do PublicKey, PublicKeyType, PoolID, - RevokeID, + HashIDPreimageRevokeID, SequenceNumber, UInt32, UInt256, @@ -76,7 +76,7 @@ defmodule Stellar.TxBuild.RevokeIDTest do public_key: public_key, pool_id_value: pool_id_value } do - %RevokeID{ + %HashIDPreimageRevokeID{ source_account: %AccountID{ account_id: %PublicKey{ public_key: %UInt256{ @@ -87,7 +87,7 @@ defmodule Stellar.TxBuild.RevokeIDTest do type: %PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} } }, - sequence_number: %SequenceNumber{sequence_number: 123}, + seq_num: %SequenceNumber{sequence_number: 123}, op_num: %UInt32{datum: 123}, liquidity_pool_id: %PoolID{ value: diff --git a/test/tx_build/hash_id_preimage_soroban_authorization_test.exs b/test/tx_build/hash_id_preimage_soroban_authorization_test.exs new file mode 100644 index 00000000..2d449a06 --- /dev/null +++ b/test/tx_build/hash_id_preimage_soroban_authorization_test.exs @@ -0,0 +1,150 @@ +defmodule Stellar.TxBuild.HashIDPreimageSorobanAuthorizationTest do + use ExUnit.Case + + import Stellar.Test.XDRFixtures, only: [soroban_auth_xdr: 4] + + alias Stellar.TxBuild.{ + HashIDPreimageSorobanAuthorization, + SCVec, + SCVal, + SCAddress, + SorobanAuthorizedContractFunction, + SorobanAuthorizedFunction, + SorobanAuthorizedInvocation + } + + setup do + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + + contract_address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + function_name = "hello" + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + + soroban_function = SorobanAuthorizedFunction.new(contract_fn: contract_fn) + + network_id = "nerwork_id" + nonce = 1234 + signature_expiration_ledger = 5678 + invocation = SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + xdr = soroban_auth_xdr(network_id, nonce, signature_expiration_ledger, invocation) + + %{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation, + xdr: xdr + } + end + + test "new/1", %{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + } do + %HashIDPreimageSorobanAuthorization{ + network_id: ^network_id, + nonce: ^nonce, + signature_expiration_ledger: ^signature_expiration_ledger, + invocation: ^invocation + } = + HashIDPreimageSorobanAuthorization.new( + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + ) + end + + test "new/1 with invalid args" do + {:error, :invalid_preimage_soroban_auth} = + HashIDPreimageSorobanAuthorization.new("invalid_args") + end + + test "new/1 with invalid network_id", %{ + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + } do + {:error, :invalid_network_id} = + HashIDPreimageSorobanAuthorization.new( + network_id: 1234, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + ) + end + + test "new/1 with invalid nonce", %{ + network_id: network_id, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + } do + {:error, :invalid_nonce} = + HashIDPreimageSorobanAuthorization.new( + network_id: network_id, + nonce: "invalid", + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + ) + end + + test "new/1 with invalid signature_expiration_ledger", %{ + network_id: network_id, + nonce: nonce, + invocation: invocation + } do + {:error, :invalid_signature_expiration_ledger} = + HashIDPreimageSorobanAuthorization.new( + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: "invalid", + invocation: invocation + ) + end + + test "new/1 with invalid invocation", %{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + } do + {:error, :invalid_invocation} = + HashIDPreimageSorobanAuthorization.new( + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: "invalid" + ) + end + + test "to_xdr/1", + %{ + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation, + xdr: xdr + } do + ^xdr = + HashIDPreimageSorobanAuthorization.new( + network_id: network_id, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + invocation: invocation + ) + |> HashIDPreimageSorobanAuthorization.to_xdr() + end + + test "to_xdr/1 when the struct is invalid" do + {:error, :invalid_struct_revoke_id} = + HashIDPreimageSorobanAuthorization.to_xdr("invalid_struct") + end +end diff --git a/test/tx_build/hash_id_preimage_test.exs b/test/tx_build/hash_id_preimage_test.exs index 9216c3e4..10a2ca65 100644 --- a/test/tx_build/hash_id_preimage_test.exs +++ b/test/tx_build/hash_id_preimage_test.exs @@ -1,97 +1,89 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do use ExUnit.Case + alias Stellar.TxBuild.SCAddress, as: TxSCAddress + alias Stellar.TxBuild.SorobanAuthorizedContractFunction, as: TxSorobanAuthorizedContractFunction + alias Stellar.TxBuild.SorobanAuthorizedFunction, as: TxSorobanAuthorizedFunction + alias Stellar.TxBuild.SorobanAuthorizedInvocation, as: TxSorobanAuthorizedInvocation + + alias Stellar.TxBuild.HashIDPreimageSorobanAuthorization, + as: TxHashIDPreimageSorobanAuthorization + + alias Stellar.TxBuild.ContractIDPreimage, as: TxContactIDPreimage + alias Stellar.TxBuild.Asset, as: TxAsset alias Stellar.TxBuild.HashIDPreimage, as: TxHashIDPreimage - alias Stellar.TxBuild.AuthorizedInvocation, as: TxAuthorizedInvocation - alias Stellar.TxBuild.Ed25519ContractID, as: TxEd25519ContractID - alias Stellar.TxBuild.FromAsset, as: TxFromAsset - alias Stellar.TxBuild.HashIDPreimageContractAuth, as: TxHashIDPreimageContractAuth - alias Stellar.TxBuild.HashIDPreimageCreateContractArgs, as: TxHashIDPreimageCreateContractArgs alias Stellar.TxBuild.SequenceNumber, as: TxSequenceNumber - alias Stellar.TxBuild.SourceAccountContractID, as: TxSourceAccountContractID - alias Stellar.TxBuild.StructContractID, as: TxStructContractID - alias Stellar.TxBuild.SCContractExecutable, as: TxSCContractExecutable alias Stellar.TxBuild.SCVal, as: TxSCVal - alias Stellar.TxBuild.OperationID, as: TxOperationID - alias Stellar.TxBuild.RevokeID, as: TxRevokeID + alias Stellar.TxBuild.SCVec, as: TxSCVec + alias Stellar.TxBuild.HashIDPreimageOperationID, as: TxOperationID + alias Stellar.TxBuild.HashIDPreimageRevokeID, as: TxRevokeID + alias Stellar.TxBuild.HashIDPreimageContractID, as: TxHashIDPreimageContractID alias StellarBase.XDR.{ AccountID, Asset, AssetType, - AuthorizedInvocation, - AuthorizedInvocationList, - Ed25519ContractID, + ContractIDPreimage, + ContractIDPreimageType, EnvelopeType, - FromAsset, Hash, HashIDPreimage, - HashIDPreimageContractAuth, - HashIDPreimageCreateContractArgs, + HashIDPreimageContractID, Int32, - OperationID, + HashIDPreimageOperationID, PublicKey, PublicKeyType, PoolID, - RevokeID, - SourceAccountContractID, + HashIDPreimageRevokeID, + SorobanAuthorizedContractFunction, + SorobanAuthorizedFunction, + SorobanAuthorizedFunctionType, + SorobanAuthorizedInvocation, + SorobanAuthorizedInvocationList, + HashIDPreimageSorobanAuthorization, SequenceNumber, - StructContractID, - SCContractExecutable, - SCContractExecutableType, + SCAddress, + SCAddressType, SCVal, SCValType, SCVec, SCSymbol, UInt256, UInt32, - UInt64, + Int64, Void } setup do public_key = "GB6FIXFOEK46VBDAG5USXRKKDJYFOBQZDMAPOYY6MC4KMRTSPVUH3X2A" - # OperationID + # HashIDPreimageOperationID sequence_number = TxSequenceNumber.new(123_456_789) op_num = 123 - # RevokeID + # HashIDPreimageRevokeID pool_id_value = "929b20b72e5890ab51c24f1cc46fa01c4f318d8d33367d24dd614cfdf5491072" asset = :native - # Ed25519ContractID + # HashIDPreimageContractID network_id = "network_id" - ed25519 = 456 - salt = 456 - - # StructContractID - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" + contract_id_preimage = TxContactIDPreimage.new(from_asset: TxAsset.new(:native)) - # HashIDPreimageCreateContractArgs - wasm_ref_sc_contract_executable = TxSCContractExecutable.new(wasm_ref: "wasm_ref") - token_sc_contract_executable = TxSCContractExecutable.new(:token) - - # HashIDPreimageContractAuth - nonce = 987 + # SorobanAuthorizedInvocation + contract_address = TxSCAddress.new("CACGCFUMXOXA3KLMKQ5XD7KXDLWEWRCUTVID7GXZ45UFZTW3YFQTZD6Y") function_name = "function_name" - args = [TxSCVal.new(i32: 654)] + args = TxSCVec.new([TxSCVal.new(i32: 654)]) - invocation_1 = - TxAuthorizedInvocation.new( - contract_id: contract_id, + contract_function = + TxSorobanAuthorizedContractFunction.new( + contract_address: contract_address, function_name: function_name, - args: args, - sub_invocations: [] + args: args ) - invocation_2 = - TxAuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [invocation_1] - ) + function = TxSorobanAuthorizedFunction.new(contract_fn: contract_function) + + invocation = TxSorobanAuthorizedInvocation.new(function: function, sub_invocations: []) %{ operation_id: @@ -108,34 +100,17 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do liquidity_pool_id: pool_id_value, asset: asset ), - ed25519_contract_id: - TxEd25519ContractID.new(network_id: network_id, ed25519: ed25519, salt: salt), - struct_contract_id: - TxStructContractID.new(network_id: network_id, contract_id: contract_id, salt: salt), - from_asset: TxFromAsset.new(network_id: network_id, asset: asset), - source_account_contract_id: - TxSourceAccountContractID.new( - network_id: network_id, - source_account: public_key, - salt: salt - ), - hash_id_preimage_create_contract_arg_wasm_ref: - TxHashIDPreimageCreateContractArgs.new( - network_id: network_id, - executable: wasm_ref_sc_contract_executable, - salt: salt - ), - hash_id_preimage_create_contract_arg_token: - TxHashIDPreimageCreateContractArgs.new( + contract_id: + TxHashIDPreimageContractID.new( network_id: network_id, - executable: token_sc_contract_executable, - salt: salt + contract_id_preimage: contract_id_preimage ), - hash_id_preimage_contract_auth: - TxHashIDPreimageContractAuth.new( + soroban_auth: + TxHashIDPreimageSorobanAuthorization.new( network_id: network_id, - nonce: nonce, - invocation: invocation_2 + nonce: 123_185, + signature_expiration_ledger: 123_541, + invocation: invocation ) } end @@ -158,87 +133,24 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do {:error, :invalid_pool_revoke_op_id} = TxHashIDPreimage.new(pool_revoke_op_id: :wrong_value) end - test "new/1 when type is contract_id_from_ed25519", %{ed25519_contract_id: ed25519_contract_id} do - %TxHashIDPreimage{type: :contract_id_from_ed25519, value: ^ed25519_contract_id} = - TxHashIDPreimage.new(contract_id_from_ed25519: ed25519_contract_id) + test "new/1 when type is contract_id", %{contract_id: contract_id} do + %TxHashIDPreimage{type: :contract_id, value: ^contract_id} = + TxHashIDPreimage.new(contract_id: contract_id) end - test "new/1 when contract_id_from_ed25519 value is wrong" do - {:error, :invalid_contract_id_from_ed25519} = - TxHashIDPreimage.new(contract_id_from_ed25519: :wrong_value) - end - - test "new/1 when type is contract_id_from_contract", %{struct_contract_id: struct_contract_id} do - %TxHashIDPreimage{type: :contract_id_from_contract, value: ^struct_contract_id} = - TxHashIDPreimage.new(contract_id_from_contract: struct_contract_id) - end - - test "new/1 when contract_id_from_contract value is wrong" do - {:error, :invalid_contract_id_from_contract} = - TxHashIDPreimage.new(contract_id_from_contract: :wrong_value) - end - - test "new/1 when type is contract_id_from_asset", %{from_asset: from_asset} do - %TxHashIDPreimage{type: :contract_id_from_asset, value: ^from_asset} = - TxHashIDPreimage.new(contract_id_from_asset: from_asset) - end - - test "new/1 when contract_id_from_asset value is wrong" do - {:error, :invalid_contract_id_from_asset} = - TxHashIDPreimage.new(contract_id_from_asset: :wrong_value) - end - - test "new/1 when type is contact_id_from_source_acc", %{ - source_account_contract_id: source_account_contract_id - } do - %TxHashIDPreimage{type: :contact_id_from_source_acc, value: ^source_account_contract_id} = - TxHashIDPreimage.new(contact_id_from_source_acc: source_account_contract_id) + test "new/1 when contract_id value is wrong" do + {:error, :invalid_contract_id} = TxHashIDPreimage.new(contract_id: :wrong_value) end test "new/1 with invalid args" do {:error, :invalid_hash_id_preimage_type} = TxHashIDPreimage.new("invalid_args") end - test "new/1 when contact_id_from_source_acc value is wrong" do - {:error, :invalid_contact_id_from_source_acc} = - TxHashIDPreimage.new(contact_id_from_source_acc: :wrong_value) - end - - test "new/1 when type is create_contract_args and the code is wasm_ref", %{ - hash_id_preimage_create_contract_arg_wasm_ref: hash_id_preimage_create_contract_arg - } do - %TxHashIDPreimage{type: :create_contract_args, value: ^hash_id_preimage_create_contract_arg} = - TxHashIDPreimage.new(create_contract_args: hash_id_preimage_create_contract_arg) - end - - test "new/1 when type is create_contract_args and the code is token", %{ - hash_id_preimage_create_contract_arg_token: hash_id_preimage_create_contract_arg - } do - %TxHashIDPreimage{type: :create_contract_args, value: ^hash_id_preimage_create_contract_arg} = - TxHashIDPreimage.new(create_contract_args: hash_id_preimage_create_contract_arg) - end - - test "new/1 when create_contract_args value is wrong" do - {:error, :invalid_create_contract_args} = - TxHashIDPreimage.new(create_contract_args: :wrong_value) - end - - test "new/1 when type is contract_auth", %{ - hash_id_preimage_contract_auth: hash_id_preimage_contract_auth - } do - %TxHashIDPreimage{type: :contract_auth, value: ^hash_id_preimage_contract_auth} = - TxHashIDPreimage.new(contract_auth: hash_id_preimage_contract_auth) - end - - test "new/1 when contract_auth value is wrong" do - {:error, :invalid_contract_auth} = TxHashIDPreimage.new(contract_auth: :wrong_value) - end - test "to_xdr/1 when type is op_id", %{operation_id: operation_id} do %HashIDPreimage{ - hash_id: %OperationID{ + value: %HashIDPreimageOperationID{ op_num: %UInt32{datum: 123}, - sequence_number: %SequenceNumber{sequence_number: 123_456_789}, + seq_num: %SequenceNumber{sequence_number: 123_456_789}, source_account: %AccountID{ account_id: %PublicKey{ public_key: %UInt256{ @@ -258,7 +170,7 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do test "to_xdr/1 when type is pool_revoke_op_id", %{revoke_id: revoke_id} do %HashIDPreimage{ - hash_id: %RevokeID{ + value: %HashIDPreimageRevokeID{ source_account: %AccountID{ account_id: %PublicKey{ public_key: %UInt256{ @@ -269,7 +181,7 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do type: %PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} } }, - sequence_number: %SequenceNumber{sequence_number: 123_456_789}, + seq_num: %SequenceNumber{sequence_number: 123_456_789}, op_num: %UInt32{datum: 123}, liquidity_pool_id: %PoolID{ value: @@ -287,153 +199,69 @@ defmodule Stellar.TxBuild.HashIDPreimageTest do |> TxHashIDPreimage.to_xdr() end - test "to_xdr/1 when type is contract_id_from_ed25519", %{ - ed25519_contract_id: ed25519_contract_id - } do - %HashIDPreimage{ - hash_id: %Ed25519ContractID{ - ed25519: %UInt256{datum: 456}, - network_id: %Hash{value: "network_id"}, - salt: %UInt256{datum: 456} - }, - type: %EnvelopeType{ - identifier: :ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519 - } - } = - TxHashIDPreimage.new(contract_id_from_ed25519: ed25519_contract_id) - |> TxHashIDPreimage.to_xdr() - end - - test "to_xdr/1 when type is contract_id_from_contract", %{ - struct_contract_id: struct_contract_id - } do - %HashIDPreimage{ - hash_id: %StructContractID{ - network_id: %Hash{value: "network_id"}, - contract_id: %Hash{ - value: "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - }, - salt: %UInt256{datum: 456} - }, - type: %EnvelopeType{identifier: :ENVELOPE_TYPE_POOL_REVOKE_OP_ID} - } = - TxHashIDPreimage.new(contract_id_from_contract: struct_contract_id) - |> TxHashIDPreimage.to_xdr() - end - - test "to_xdr/1 when type is contract_id_from_asset", %{from_asset: from_asset} do - %HashIDPreimage{ - hash_id: %FromAsset{ - network_id: %Hash{value: "network_id"}, - asset: %Asset{ - asset: %Void{value: nil}, - type: %AssetType{identifier: :ASSET_TYPE_NATIVE} - } - }, - type: %EnvelopeType{identifier: :ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET} - } = - TxHashIDPreimage.new(contract_id_from_asset: from_asset) - |> TxHashIDPreimage.to_xdr() - end - - test "to_xdr/1 when type is contact_id_from_source_acc", %{ - source_account_contract_id: source_account_contract_id - } do - %HashIDPreimage{ - hash_id: %SourceAccountContractID{ - network_id: %Hash{value: "network_id"}, - salt: %UInt256{datum: 456}, - source_account: %AccountID{ - account_id: %PublicKey{ - public_key: %UInt256{ - datum: - <<124, 84, 92, 174, 34, 185, 234, 132, 96, 55, 105, 43, 197, 74, 26, 112, 87, 6, - 25, 27, 0, 247, 99, 30, 96, 184, 166, 70, 114, 125, 104, 125>> - }, - type: %PublicKeyType{ - identifier: :PUBLIC_KEY_TYPE_ED25519 - } - } - } - }, - type: %EnvelopeType{ - identifier: :ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT - } - } = - TxHashIDPreimage.new(contact_id_from_source_acc: source_account_contract_id) - |> TxHashIDPreimage.to_xdr() - end - - test "to_xdr/1 when type is create_contract_args", %{ - hash_id_preimage_create_contract_arg_token: hash_id_preimage_create_contract_arg - } do + test "to_xdr/1 when type is contract_id", %{contract_id: contract_id} do %HashIDPreimage{ - hash_id: %HashIDPreimageCreateContractArgs{ + value: %HashIDPreimageContractID{ network_id: %Hash{value: "network_id"}, - salt: %UInt256{datum: 456}, - executable: %SCContractExecutable{ - contract_executable: %Void{value: nil}, - type: %SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_TOKEN + contract_id_preimage: %ContractIDPreimage{ + value: %Asset{ + asset: %Void{value: nil}, + type: %AssetType{identifier: :ASSET_TYPE_NATIVE} + }, + type: %ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ASSET } } }, - type: %EnvelopeType{ - identifier: :ENVELOPE_TYPE_CREATE_CONTRACT_ARGS - } + type: %EnvelopeType{identifier: :ENVELOPE_TYPE_CONTRACT_ID} } = - TxHashIDPreimage.new(create_contract_args: hash_id_preimage_create_contract_arg) + TxHashIDPreimage.new(contract_id: contract_id) |> TxHashIDPreimage.to_xdr() end - test "to_xdr/1 when type is contract_auth", %{ - hash_id_preimage_contract_auth: hash_id_preimage_contract_auth - } do + test "to_xdr/1 when type is soroban_auth", %{soroban_auth: soroban_auth} do %HashIDPreimage{ - hash_id: %HashIDPreimageContractAuth{ + value: %HashIDPreimageSorobanAuthorization{ network_id: %Hash{value: "network_id"}, - nonce: %UInt64{datum: 987}, - invocation: %AuthorizedInvocation{ - contract_id: %Hash{ - value: - <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, 84, - 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> - }, - function_name: %SCSymbol{value: "function_name"}, - args: %SCVec{ - sc_vals: [ - %SCVal{ - value: %Int32{datum: 654}, - type: %SCValType{identifier: :SCV_I32} - } - ] - }, - sub_invocations: %AuthorizedInvocationList{ - sub_invocations: [ - %AuthorizedInvocation{ - contract_id: %Hash{ + nonce: %Int64{datum: 123_185}, + signature_expiration_ledger: %UInt32{datum: 123_541}, + invocation: %SorobanAuthorizedInvocation{ + function: %SorobanAuthorizedFunction{ + value: %SorobanAuthorizedContractFunction{ + contract_address: %SCAddress{ + sc_address: %Hash{ value: <<4, 97, 22, 140, 187, 174, 13, 169, 108, 84, 59, 113, 253, 87, 26, 236, 75, 68, 84, 157, 80, 63, 154, 249, 231, 104, 92, 206, 219, 193, 97, 60>> }, - function_name: %SCSymbol{value: "function_name"}, - args: %SCVec{ - sc_vals: [ - %SCVal{ - value: %Int32{datum: 654}, - type: %SCValType{identifier: :SCV_I32} - } - ] - }, - sub_invocations: %AuthorizedInvocationList{sub_invocations: []} + type: %SCAddressType{ + identifier: :SC_ADDRESS_TYPE_CONTRACT + } + }, + function_name: %SCSymbol{value: "function_name"}, + args: %SCVec{ + items: [ + %SCVal{ + value: %Int32{datum: 654}, + type: %SCValType{identifier: :SCV_I32} + } + ] } - ] + }, + type: %SorobanAuthorizedFunctionType{ + identifier: :SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN + } + }, + sub_invocations: %SorobanAuthorizedInvocationList{ + items: [] } } }, - type: %EnvelopeType{identifier: :ENVELOPE_TYPE_CONTRACT_AUTH} + type: %EnvelopeType{ + identifier: :ENVELOPE_TYPE_SOROBAN_AUTHORIZATION + } } = - TxHashIDPreimage.new(contract_auth: hash_id_preimage_contract_auth) + TxHashIDPreimage.new(soroban_auth: soroban_auth) |> TxHashIDPreimage.to_xdr() end end diff --git a/test/tx_build/host_function_args_test.exs b/test/tx_build/host_function_args_test.exs deleted file mode 100644 index c72d0983..00000000 --- a/test/tx_build/host_function_args_test.exs +++ /dev/null @@ -1,250 +0,0 @@ -defmodule Stellar.TxBuild.HostFunctionArgsArgsTest do - use ExUnit.Case - - alias Stellar.TxBuild.{Asset, HostFunctionArgs, SCVal} - - import Stellar.Test.XDRFixtures, - only: [ - host_function_xdr: 4, - host_function_upload_xdr: 2, - host_function_create_with_wasm_xdr: 3, - host_function_create_with_asset: 1 - ] - - describe "HostFunctionArgs invoke" do - setup do - type = :invoke - upload_type = :upload - create_type = :create - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "hello" - args = [SCVal.new(symbol: "world")] - - code = - <<0, 97, 115, 109, 1, 0, 0, 0, 1, 19, 4, 96, 1, 126, 1, 126, 96, 2, 126, 126, 1, 126, 96, - 1, 127, 0, 96, 0, 0, 2, 37, 6, 1, 118, 1, 95, 0, 0, 1, 118, 1, 54, 0, 1, 1, 97, 1, 48, - 0, 0, 1, 108, 1, 48, 0, 0>> - - wasm_id = - <<86, 32, 6, 9, 172, 4, 212, 185, 249, 87, 184, 164, 58, 34, 167, 183, 226, 117, 205, 116, - 11, 130, 119, 172, 224, 51, 12, 148, 90, 251, 17, 12>> - - salt = :crypto.strong_rand_bytes(32) - - asset = Asset.new(:native) - - %{ - type: type, - upload_type: upload_type, - create_type: create_type, - contract_id: contract_id, - function_name: function_name, - args: args, - xdr: host_function_xdr(type, contract_id, function_name, args), - upload_xdr: host_function_upload_xdr(upload_type, code), - create_wasm_xdr: host_function_create_with_wasm_xdr(create_type, wasm_id, salt), - create_asset_xdr: host_function_create_with_asset(create_type), - code: code, - wasm_id: wasm_id, - salt: salt, - asset: asset - } - end - - test "new/2", %{ - type: type, - contract_id: contract_id, - function_name: function_name, - args: args - } do - %HostFunctionArgs{ - type: ^type, - contract_id: ^contract_id, - function_name: ^function_name, - args: ^args - } = - HostFunctionArgs.new( - type: type, - contract_id: contract_id, - function_name: function_name, - args: args - ) - end - - test "new/2 with_invalid_type", %{ - contract_id: contract_id, - function_name: function_name, - args: args - } do - {:error, :invalid_operation_attributes} = - HostFunctionArgs.new( - type: :invalid, - contract_id: contract_id, - function_name: function_name, - args: args - ) - end - - test "new/2 with_invalid_contract_id", %{ - type: type, - function_name: function_name, - args: args - } do - {:error, :invalid_contract_id} = - HostFunctionArgs.new( - type: type, - contract_id: "hello-not-hex-encoded-string", - function_name: function_name, - args: args - ) - end - - test "new/2 with_invalid_function_name", %{ - type: type, - contract_id: contract_id, - args: args - } do - {:error, :invalid_function_name} = - HostFunctionArgs.new( - type: type, - contract_id: contract_id, - function_name: 123, - args: args - ) - end - - test "new/2 with_invalid_args", %{ - type: type, - contract_id: contract_id, - function_name: function_name - } do - {:error, :invalid_args} = - HostFunctionArgs.new( - type: type, - contract_id: contract_id, - function_name: function_name, - args: [1, 2, 3] - ) - end - - test "new/2 when type is :upload", %{upload_type: type, code: code} do - %HostFunctionArgs{type: ^type, code: ^code} = - HostFunctionArgs.new( - type: type, - code: code - ) - end - - test "new/2 when type is :upload with invalid code", %{upload_type: type} do - {:error, :invalid_operation_attributes} = - HostFunctionArgs.new( - type: type, - code: 1234 - ) - end - - test "new/2 when type is :create with wasm_id without salt", %{ - create_type: type, - wasm_id: wasm_id - } do - %HostFunctionArgs{type: ^type, wasm_id: ^wasm_id} = - HostFunctionArgs.new( - type: type, - wasm_id: wasm_id - ) - end - - test "new/2 when type is :create with invalid wasm_id", %{create_type: type} do - {:error, :invalid_wasm_id} = - HostFunctionArgs.new( - type: type, - wasm_id: 123 - ) - end - - test "new/2 when type is :create with wasm_id and salt", %{ - create_type: type, - wasm_id: wasm_id, - salt: salt - } do - %HostFunctionArgs{type: ^type, wasm_id: ^wasm_id, salt: ^salt} = - HostFunctionArgs.new( - type: type, - wasm_id: wasm_id, - salt: salt - ) - end - - test "new/2 when type is :create with invalid salt", %{create_type: type, wasm_id: wasm_id} do - {:error, :invalid_salt} = - HostFunctionArgs.new( - type: type, - wasm_id: wasm_id, - salt: 123 - ) - end - - test "new/2 when type is :create with asset", %{create_type: type, asset: asset} do - %HostFunctionArgs{type: ^type, asset: ^asset} = - HostFunctionArgs.new( - type: type, - asset: asset - ) - end - - test "new/2 when type is :create with invalid asset", %{create_type: type} do - {:error, :invalid_asset} = - HostFunctionArgs.new( - type: type, - asset: 123 - ) - end - - test "to_xdr/1", %{ - type: type, - contract_id: contract_id, - function_name: function_name, - args: args, - xdr: xdr - } do - ^xdr = - [type: type, contract_id: contract_id, function_name: function_name, args: args] - |> HostFunctionArgs.new() - |> HostFunctionArgs.to_xdr() - end - - test "to_xdr/1 upload", %{ - upload_type: upload_type, - code: code, - upload_xdr: upload_xdr - } do - ^upload_xdr = - [type: upload_type, code: code] - |> HostFunctionArgs.new() - |> HostFunctionArgs.to_xdr() - end - - test "to_xdr/1 when type is :create with wasm_id", %{ - create_type: type, - wasm_id: wasm_id, - salt: salt, - create_wasm_xdr: xdr - } do - ^xdr = - [type: type, wasm_id: wasm_id, salt: salt] - |> HostFunctionArgs.new() - |> HostFunctionArgs.to_xdr() - end - - test "to_xdr/1 when type is :create with asset", %{ - create_type: type, - asset: asset, - create_asset_xdr: xdr - } do - ^xdr = - [type: type, asset: asset] - |> HostFunctionArgs.new() - |> HostFunctionArgs.to_xdr() - end - end -end diff --git a/test/tx_build/host_function_test.exs b/test/tx_build/host_function_test.exs index 30032fdb..9f3e1102 100644 --- a/test/tx_build/host_function_test.exs +++ b/test/tx_build/host_function_test.exs @@ -1,158 +1,129 @@ defmodule Stellar.TxBuild.HostFunctionTest do use ExUnit.Case - alias StellarBase.XDR.HostFunction, as: HostFunctionXDR - alias Stellar.TxBuild.{ - AddressWithNonce, - AuthorizedInvocation, - ContractAuth, + ContractExecutable, + ContractIDPreimage, + ContractIDPreimageFromAddress, + CreateContractArgs, HostFunction, - HostFunctionArgs, SCAddress, - SCVal + SCVal, + SCVec } import Stellar.Test.XDRFixtures, - only: [ - host_function_xdr: 4, - host_function_with_auth_xdr: 4 - ] + only: [host_function_xdr: 2] - describe "HostFunction invoke" do + describe "HostFunction" do setup do - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "hello" - args = [SCVal.new(symbol: "world")] - sc_address = SCAddress.new("GARVXS4KWSI6UQWZL2AAIB2KD4MAXG27YOE6IE64THZRSASAVR3ZPSUN") - address_with_nonce = AddressWithNonce.new(address: sc_address, nonce: 123) - - authorized_invocation_1 = - AuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [] - ) + # :invoke_contract + contract_address = + "CACGCFUMXOXA3KLMKQ5XD7KXDLWEWRCUTVID7GXZ45UFZTW3YFQTZD6Y" + |> SCAddress.new() + |> (&SCVal.new(address: &1)).() - authorized_invocation_2 = - AuthorizedInvocation.new( - contract_id: contract_id, - function_name: function_name, - args: args, - sub_invocations: [authorized_invocation_1] - ) + function_name = SCVal.new(symbol: "hello") + invoke_args = SCVec.new([contract_address, function_name, SCVal.new(symbol: "world")]) + + # :create_contract + wasm_id = + <<86, 32, 6, 9, 172, 4, 212, 185, 249, 87, 184, 164, 58, 34, 167, 183, 226, 117, 205, 116, + 11, 130, 119, 172, 224, 51, 12, 148, 90, 251, 17, 12>> - contract_authentication = - ContractAuth.new( - address_with_nonce: address_with_nonce, - authorized_invocation: authorized_invocation_2, - args: args + contract_executable = ContractExecutable.new(wasm_ref: wasm_id) + sc_address = SCAddress.new("GARVXS4KWSI6UQWZL2AAIB2KD4MAXG27YOE6IE64THZRSASAVR3ZPSUN") + # :crypto.strong_rand_bytes(32) + salt = + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, + 216, 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + + from_address = ContractIDPreimageFromAddress.new(address: sc_address, salt: salt) + contract_id_preimage = ContractIDPreimage.new(from_address: from_address) + + create_contract_args = + CreateContractArgs.new( + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable ) - contract_auth_strs = [ - "AAAAAQAAAAAAAAAAI1vLirSR6kLZXoAEB0ofGAubX8OJ5BPcmfMZAkCsd5cAAAAAAAAAewRhFoy7rg2pbFQ7cf1XGuxLRFSdUD+a+edoXM7bwWE8AAAABWhlbGxvAAAAAAAAAQAAAA8AAAAFd29ybGQAAAAAAAABBGEWjLuuDalsVDtx/Vca7EtEVJ1QP5r552hcztvBYTwAAAAFaGVsbG8AAAAAAAABAAAADwAAAAV3b3JsZAAAAAAAAAAAAAABAAAAEAAAAAEAAAAA" - ] + # :upload_contract_wasm + code = + <<0, 97, 115, 109, 1, 0, 0, 0, 1, 19, 4, 96, 1, 126, 1, 126, 96, 2, 126, 126, 1, 126, 96, + 1, 127, 0, 96, 0, 0, 2, 37, 6, 1, 118, 1, 95, 0, 0, 1, 118, 1, 54, 0, 1, 1, 97, 1, 48, + 0, 0, 1, 108, 1, 48, 0, 0>> - function_args = - HostFunctionArgs.new( - type: :invoke, - contract_id: contract_id, - function_name: function_name, - args: args - ) + upload_contract_wasm_args = code %{ - function_args: function_args, - contract_authentication: contract_authentication, - contract_auth_strs: contract_auth_strs, - host_function: HostFunction.new(args: function_args), - host_function_with_auth: - HostFunction.new(args: function_args, auth: [contract_authentication]), - host_function_xdr: host_function_xdr(:invoke, contract_id, function_name, args), - host_function_with_auth_xdr: - host_function_with_auth_xdr(:invoke, contract_id, function_name, args) + invoke_args: invoke_args, + invoke_host_function: HostFunction.new(invoke_contract: invoke_args), + host_function_xdr: host_function_xdr(:invoke_contract, invoke_args), + create_contract_args: create_contract_args, + create_contract_function: HostFunction.new(create_contract: create_contract_args), + create_contract_xdr: host_function_xdr(:create_contract, create_contract_args), + upload_contract_wasm_args: upload_contract_wasm_args, + upload_contract_wasm_function: + HostFunction.new(upload_contract_wasm: upload_contract_wasm_args), + upload_contract_wasm_xdr: + host_function_xdr(:upload_contract_wasm, upload_contract_wasm_args) } end - test "new/2", %{ - function_args: function_args + test "new/2 invoke_contract", %{ + invoke_args: invoke_args } do %HostFunction{ - args: ^function_args - } = HostFunction.new(args: function_args) + type: :invoke_contract, + value: ^invoke_args + } = HostFunction.new(invoke_contract: invoke_args) end - test "new/2 with auth", %{ - function_args: function_args, - contract_authentication: contract_authentication + test "new/2 create_contract", %{ + create_contract_args: create_contract_args } do %HostFunction{ - args: ^function_args - } = HostFunction.new(args: function_args, auth: [contract_authentication]) + type: :create_contract, + value: ^create_contract_args + } = HostFunction.new(create_contract: create_contract_args) end - test "new/2 invalid attributes" do - {:error, :invalid_operation_attributes} = HostFunction.new(:invalid) - end - - test "new/2 invalid args" do - {:error, :invalid_args} = HostFunction.new(args: :invalid) - end - - test "new/2 invalid auth", %{function_args: function_args} do - {:error, :invalid_auth} = HostFunction.new(args: function_args, auth: [123]) - end - - test "set_auth/2", %{ - function_args: function_args, - host_function: host_function, - contract_auth_strs: contract_auth_strs + test "new/2 upload_contract_wasm", %{ + upload_contract_wasm_args: upload_contract_wasm_args } do %HostFunction{ - args: ^function_args, - auth: ^contract_auth_strs - } = HostFunction.set_auth(host_function, contract_auth_strs) + type: :upload_contract_wasm, + value: ^upload_contract_wasm_args + } = HostFunction.new(upload_contract_wasm: upload_contract_wasm_args) end - test "set_auth/2 nil auth str", %{ - function_args: function_args, - host_function: host_function - } do - %HostFunction{ - args: ^function_args, - auth: [nil] - } = HostFunction.set_auth(host_function, [nil]) + test "new/2 invalid attributes" do + {:error, :invalid_operation_attributes} = HostFunction.new(:invalid) end - test "set_auth/2 invalid xdr string", %{host_function: host_function} do - {:error, :invalid_auth} = HostFunction.set_auth(host_function, ["invalid"]) + test "new/2 invalid host function value" do + {:error, :invalid_create_contract} = HostFunction.new(create_contract: :invalid) end - test "to_xdr/1", %{ + test "to_xdr/1 invoke_contract", %{ host_function_xdr: host_function_xdr, - host_function: host_function + invoke_host_function: invoke_host_function } do - %HostFunctionXDR{args: ^host_function_xdr} = HostFunction.to_xdr(host_function) + ^host_function_xdr = HostFunction.to_xdr(invoke_host_function) end - test "to_xdr/1 with auth", %{ - host_function_with_auth_xdr: host_function_with_auth_xdr, - host_function_with_auth: host_function_with_auth + test "to_xdr/1 create_contract", %{ + create_contract_xdr: create_contract_xdr, + create_contract_function: create_contract_function } do - # %HostFunctionXDR{args: ^host_function_xdr} - ^host_function_with_auth_xdr = HostFunction.to_xdr(host_function_with_auth) + ^create_contract_xdr = HostFunction.to_xdr(create_contract_function) end - test "to_xdr/1 with auth strs", %{ - host_function_with_auth_xdr: host_function_with_auth_xdr, - host_function: host_function, - contract_auth_strs: contract_auth_strs + test "to_xdr/1 upload_contract_wasm", %{ + upload_contract_wasm_xdr: upload_contract_wasm_xdr, + upload_contract_wasm_function: upload_contract_wasm_function } do - ^host_function_with_auth_xdr = - host_function - |> HostFunction.set_auth(contract_auth_strs) - |> HostFunction.to_xdr() + ^upload_contract_wasm_xdr = HostFunction.to_xdr(upload_contract_wasm_function) end end end diff --git a/test/tx_build/invoke_host_function_test.exs b/test/tx_build/invoke_host_function_test.exs index c951f5a5..5c7fe452 100644 --- a/test/tx_build/invoke_host_function_test.exs +++ b/test/tx_build/invoke_host_function_test.exs @@ -3,78 +3,122 @@ defmodule Stellar.TxBuild.InvokeHostFunctionTest do alias Stellar.TxBuild.{ HostFunction, - HostFunctionArgs, InvokeHostFunction, - OptionalAccount, - SCVal + SCAddress, + SCVal, + SCVec, + SorobanAuthorizedContractFunction, + SorobanAuthorizedFunction, + SorobanAuthorizedInvocation, + SorobanCredentials, + SorobanAuthorizationEntry } - import Stellar.Test.XDRFixtures, - only: [ - invoke_host_function_op_xdr: 1 - ] + import Stellar.Test.XDRFixtures, only: [invoke_host_function_op_xdr: 1] describe "InvokeHostFunction" do setup do - type = :invoke - contract_id = "0461168cbbae0da96c543b71fd571aec4b44549d503f9af9e7685ccedbc1613c" - function_name = "hello" - args = [SCVal.new(symbol: "world")] - source_account = "GARVXS4KWSI6UQWZL2AAIB2KD4MAXG27YOE6IE64THZRSASAVR3ZPSUN" - - function_args = - HostFunctionArgs.new( - type: type, - contract_id: contract_id, - function_name: function_name, - args: args + sc_contract_address = + SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + contract_address = SCVal.new(address: sc_contract_address) + function_name = SCVal.new(symbol: "hello") + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + args = SCVec.new([contract_address, function_name, SCVal.new(string: "dev")]) + + host_function = HostFunction.new(invoke_contract: args) + + invoke_host_function_op = InvokeHostFunction.new(host_function: host_function, auths: []) + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: sc_contract_address, + function_name: "hello", + args: fn_args ) - host_functions = [HostFunction.new(args: function_args)] + soroban_function = SorobanAuthorizedFunction.new(contract_fn: contract_fn) + + root_invocation = + SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + + credentials = SorobanCredentials.new(source_account: nil) + + auths = [ + SorobanAuthorizationEntry.new(credentials: credentials, root_invocation: root_invocation) + ] + + base_64_auths = [ + "AAAAAAAAAAAAAAABZ+A/h5d/0pJnw7wmIzptCvWoX0md87QkHN68pAOfYjgAAAADaW5jAAAAAAIAAAASAAAAAAAAAABaOyGfG/GU6itO0ElcKHcFqVS+fbN5bGtw0yDCwWKx2gAAAAkAAAAAAAAAAAAAAAAAAAACAAAAAA==" + ] %{ - host_functions: host_functions, - source_account: source_account, - invoke_host_function: InvokeHostFunction.new(functions: host_functions), - xdr: invoke_host_function_op_xdr(host_functions) + host_function: host_function, + invoke_host_function_op: invoke_host_function_op, + auths: auths, + base_64_auths: base_64_auths, + xdr: invoke_host_function_op_xdr(host_function) } end - test "new/2", %{host_functions: host_functions} do + test "new/2 without auths", %{host_function: host_function} do %InvokeHostFunction{ - functions: ^host_functions - } = InvokeHostFunction.new(functions: host_functions) + host_function: ^host_function + } = InvokeHostFunction.new(host_function: host_function) end - test "new/2 with source_account", %{ - host_functions: host_functions, - source_account: source_account - } do + test "new/2 with auths", %{host_function: host_function, auths: auths} do %InvokeHostFunction{ - functions: ^host_functions, - source_account: %OptionalAccount{ - account_id: ^source_account - } + host_function: ^host_function, + auths: ^auths + } = InvokeHostFunction.new(host_function: host_function, auths: auths) + end + + test "new/2 with base 64 auths", %{host_function: host_function, base_64_auths: base_64_auths} do + %InvokeHostFunction{ + host_function: ^host_function, + auths: ^base_64_auths } = - InvokeHostFunction.new( - functions: host_functions, - source_account: source_account - ) + InvokeHostFunction.new(host_function: host_function) + |> InvokeHostFunction.set_auth(base_64_auths) + end + + test "new/2 invalid host_function" do + {:error, :invalid_host_host_function} = + InvokeHostFunction.new(host_function: :invalid, auths: []) + end + + test "new/2 invalid auths", %{host_function: host_function} do + {:error, :invalid_soroban_auth_entries} = + InvokeHostFunction.new(host_function: host_function, auths: [:invalid]) end - test "new/2 invalid attributes" do - {:error, :invalid_operation_attributes} = InvokeHostFunction.new("invalid") + test "new/2 invalid auths list", %{host_function: host_function} do + {:error, :invalid_soroban_auth_entries} = + InvokeHostFunction.new(host_function: host_function, auths: :invalid) end - test "new/2 invalid host function" do - {:error, :invalid_host_function_list} = InvokeHostFunction.new(functions: [:invalid]) + test "new/2 with invalid base 64 auths", %{ + host_function: host_function + } do + {:error, :invalid_auth} = + InvokeHostFunction.new(host_function: host_function) + |> InvokeHostFunction.set_auth(["invalid"]) + end + + test "new/2 with invalid list of base 64 auths", %{ + host_function: host_function + } do + {:error, :invalid_auth} = + InvokeHostFunction.new(host_function: host_function) + |> InvokeHostFunction.set_auth(:invalid) end test "to_xdr/1", %{ - invoke_host_function: invoke_host_function, + invoke_host_function_op: invoke_host_function_op, xdr: xdr } do - ^xdr = InvokeHostFunction.to_xdr(invoke_host_function) + ^xdr = InvokeHostFunction.to_xdr(invoke_host_function_op) end end end diff --git a/test/tx_build/optional_address_with_nonce_test.exs b/test/tx_build/optional_address_with_nonce_test.exs deleted file mode 100644 index c36a411a..00000000 --- a/test/tx_build/optional_address_with_nonce_test.exs +++ /dev/null @@ -1,70 +0,0 @@ -defmodule Stellar.TxBuild.OptionalAddressWithNonceTest do - use ExUnit.Case - - alias Stellar.TxBuild.{OptionalAddressWithNonce, AddressWithNonce, SCAddress} - - setup do - address = SCAddress.new("GB6FIXFOEK46VBDAG5USXRKKDJYFOBQZDMAPOYY6MC4KMRTSPVUH3X2A") - nonce = 123 - address_with_nonce = AddressWithNonce.new(address: address, nonce: nonce) - optional_address_with_nonce = OptionalAddressWithNonce.new(address_with_nonce) - - %{ - address_with_nonce: address_with_nonce, - optional_address_with_nonce: optional_address_with_nonce - } - end - - test "new/1", %{ - address_with_nonce: address_with_nonce - } do - %OptionalAddressWithNonce{address_with_nonce: ^address_with_nonce} = - OptionalAddressWithNonce.new(address_with_nonce) - end - - test "new/2 with_nil_value" do - %OptionalAddressWithNonce{address_with_nonce: nil} = OptionalAddressWithNonce.new(nil) - end - - test "new/2 with invalid address with nonce" do - {:error, :invalid_optional_address_with_nonce} = OptionalAddressWithNonce.new("invalid_value") - end - - test "to_xdr/1", %{ - address_with_nonce: address_with_nonce - } do - %StellarBase.XDR.OptionalAddressWithNonce{ - address_with_nonce: %StellarBase.XDR.AddressWithNonce{ - address: %StellarBase.XDR.SCAddress{ - sc_address: %StellarBase.XDR.AccountID{ - account_id: %StellarBase.XDR.PublicKey{ - public_key: %StellarBase.XDR.UInt256{ - datum: - <<124, 84, 92, 174, 34, 185, 234, 132, 96, 55, 105, 43, 197, 74, 26, 112, 87, 6, - 25, 27, 0, 247, 99, 30, 96, 184, 166, 70, 114, 125, 104, 125>> - }, - type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} - } - }, - type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} - }, - nonce: %StellarBase.XDR.UInt64{datum: 123} - } - } = - address_with_nonce - |> OptionalAddressWithNonce.new() - |> OptionalAddressWithNonce.to_xdr() - end - - test "to_xdr/1 with_nil_value" do - %StellarBase.XDR.OptionalAddressWithNonce{address_with_nonce: nil} = - nil - |> OptionalAddressWithNonce.new() - |> OptionalAddressWithNonce.to_xdr() - end - - test "to_xdr/1 when the struct is invalid" do - {:error, :invalid_struct_optional_address_with_nonce} = - OptionalAddressWithNonce.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/sc_contract_executable_test.exs b/test/tx_build/sc_contract_executable_test.exs deleted file mode 100644 index 455e6c9f..00000000 --- a/test/tx_build/sc_contract_executable_test.exs +++ /dev/null @@ -1,58 +0,0 @@ -defmodule Stellar.TxBuild.SCContractExecutableTest do - use ExUnit.Case - - alias Stellar.TxBuild.SCContractExecutable, as: TxSCContractExecutable - alias StellarBase.XDR.{SCContractExecutable, SCContractExecutableType, Hash, Void} - - setup do - %{ - hash: "example" - } - end - - test "new/1 when type is wasm_ref", %{hash: hash} do - %TxSCContractExecutable{ - type: :wasm_ref, - value: ^hash - } = TxSCContractExecutable.new(wasm_ref: hash) - end - - test "new/1 when type is token" do - %TxSCContractExecutable{ - type: :token, - value: nil - } = TxSCContractExecutable.new(:token) - end - - test "new/1 with invalid type", %{hash: hash} do - {:error, :invalid_sc_contract_executable} = TxSCContractExecutable.new(any: hash) - end - - test "new/1 with invalid args" do - {:error, :invalid_sc_contract_executable} = TxSCContractExecutable.new("invalid_args") - end - - test "new/1 with wasm invalid hash" do - {:error, :invalid_contract_hash} = TxSCContractExecutable.new(wasm_ref: 123) - end - - test "to_xdr/1 with type is wasm_ref", %{hash: hash} do - %SCContractExecutable{ - contract_executable: %Hash{value: ^hash}, - type: %SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_WASM_REF - } - } = TxSCContractExecutable.new(wasm_ref: hash) |> TxSCContractExecutable.to_xdr() - end - - test "to_xdr/1 with type is token" do - %SCContractExecutable{ - contract_executable: %Void{value: nil}, - type: %SCContractExecutableType{identifier: :SCCONTRACT_EXECUTABLE_TOKEN} - } = TxSCContractExecutable.new(:token) |> TxSCContractExecutable.to_xdr() - end - - test "to_xdr/1 with the struct is invalid" do - {:error, :invalid_sc_contract_executable} = TxSCContractExecutable.to_xdr("invalid_struct") - end -end diff --git a/test/tx_build/sc_error_test.exs b/test/tx_build/sc_error_test.exs new file mode 100644 index 00000000..c0a8a14c --- /dev/null +++ b/test/tx_build/sc_error_test.exs @@ -0,0 +1,129 @@ +defmodule Stellar.TxBuild.SCErrorTest do + use ExUnit.Case + + alias Stellar.TxBuild.SCError + alias StellarBase.XDR.SCError, as: SCErrorXDR + + setup do + error_discriminants = [ + %{type: :contract, code: :arith_domain}, + %{type: :wasm_vm, code: :index_bounds}, + %{type: :context, code: :invalid_input}, + %{type: :storage, code: :missing_value}, + %{type: :object, code: :existing_value}, + %{type: :crypto, code: :exceeded_limit}, + %{type: :events, code: :invalid_action}, + %{type: :budget, code: :internal_error}, + %{type: :code, code: :unexpected_type}, + %{type: :auth, code: :unexpected_size} + ] + + xdr_discriminants = [ + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_CONTRACT}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_ARITH_DOMAIN} + }, + type: :contract, + code: :arith_domain + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_WASM_VM}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_INDEX_BOUNDS} + }, + type: :wasm_vm, + code: :index_bounds + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_CONTEXT}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_INVALID_INPUT} + }, + type: :context, + code: :invalid_input + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_STORAGE}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_MISSING_VALUE} + }, + type: :storage, + code: :missing_value + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_OBJECT}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_EXISTING_VALUE} + }, + type: :object, + code: :existing_value + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_CRYPTO}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_EXCEEDED_LIMIT} + }, + type: :crypto, + code: :exceeded_limit + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_EVENTS}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_INVALID_ACTION} + }, + type: :events, + code: :invalid_action + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_BUDGET}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_INTERNAL_ERROR} + }, + type: :budget, + code: :internal_error + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_VALUE}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_UNEXPECTED_TYPE} + }, + type: :code, + code: :unexpected_type + }, + %{ + xdr: %SCErrorXDR{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_AUTH}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_UNEXPECTED_SIZE} + }, + type: :auth, + code: :unexpected_size + } + ] + + %{error_discriminants: error_discriminants, xdr_discriminants: xdr_discriminants} + end + + test "new/2", %{error_discriminants: error_discriminants} do + for %{type: type, code: code} <- error_discriminants do + %SCError{ + type: ^type, + code: ^code + } = SCError.new([{type, code}]) + end + end + + test "new/2 invalid args" do + {:error, :invalid_sc_error} = SCError.new(invalid_type: :invalid) + end + + test "to_xdr/1", %{xdr_discriminants: xdr_discriminants} do + for %{xdr: xdr, type: type, code: code} <- xdr_discriminants do + ^xdr = SCError.new([{type, code}]) |> SCError.to_xdr() + end + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SCError.to_xdr(:invalid) + end +end diff --git a/test/tx_build/sc_status_test.exs b/test/tx_build/sc_status_test.exs deleted file mode 100644 index 0e431cfb..00000000 --- a/test/tx_build/sc_status_test.exs +++ /dev/null @@ -1,173 +0,0 @@ -defmodule Stellar.TxBuild.SCStatusTest do - use ExUnit.Case - - alias Stellar.TxBuild.SCStatus - - test "new/1 when type is ok", %{} do - %SCStatus{type: :ok, value: nil} = SCStatus.new(ok: nil) - end - - test "new/1 when type ok is incorrect" do - {:error, :invalid_void} = SCStatus.new(ok: :UNKNOWN) - end - - test "new/1 when type is unknown_error", %{} do - %SCStatus{type: :unknown_error, value: :UNKNOWN_ERROR_GENERAL} = - SCStatus.new(unknown_error: :UNKNOWN_ERROR_GENERAL) - end - - test "new/1 when type unknown_error is incorrect" do - {:error, :invalid_unknown_error} = SCStatus.new(unknown_error: :UNKNOWN) - end - - test "new/1 when type is host_value_error", %{} do - %SCStatus{type: :host_value_error, value: :HOST_VALUE_UNKNOWN_ERROR} = - SCStatus.new(host_value_error: :HOST_VALUE_UNKNOWN_ERROR) - end - - test "new/1 when type host_value_error is incorrect" do - {:error, :invalid_host_value_error} = SCStatus.new(host_value_error: :UNKNOWN) - end - - test "new/1 when type is host_object_error", %{} do - %SCStatus{type: :host_object_error, value: :HOST_OBJECT_UNKNOWN_ERROR} = - SCStatus.new(host_object_error: :HOST_OBJECT_UNKNOWN_ERROR) - end - - test "new/1 when type host_object_error is incorrect" do - {:error, :invalid_host_object_error} = SCStatus.new(host_object_error: :UNKNOWN) - end - - test "new/1 when type is host_function_error", %{} do - %SCStatus{type: :host_function_error, value: :HOST_FN_UNKNOWN_ERROR} = - SCStatus.new(host_function_error: :HOST_FN_UNKNOWN_ERROR) - end - - test "new/1 when type host_function_error is incorrect" do - {:error, :invalid_host_function_error} = SCStatus.new(host_function_error: :UNKNOWN) - end - - test "new/1 when type is host_storage_error", %{} do - %SCStatus{type: :host_storage_error, value: :HOST_STORAGE_UNKNOWN_ERROR} = - SCStatus.new(host_storage_error: :HOST_STORAGE_UNKNOWN_ERROR) - end - - test "new/1 when type host_storage_error is incorrect" do - {:error, :invalid_host_storage_error} = SCStatus.new(host_storage_error: :UNKNOWN) - end - - test "new/1 when type is host_context_error", %{} do - %SCStatus{type: :host_context_error, value: :HOST_CONTEXT_UNKNOWN_ERROR} = - SCStatus.new(host_context_error: :HOST_CONTEXT_UNKNOWN_ERROR) - end - - test "new/1 when type host_context_error is incorrect" do - {:error, :invalid_host_context_error} = SCStatus.new(host_context_error: :UNKNOWN) - end - - test "new/1 when type is vm_error", %{} do - %SCStatus{type: :vm_error, value: :VM_UNKNOWN} = SCStatus.new(vm_error: :VM_UNKNOWN) - end - - test "new/1 when type vm_error is incorrect" do - {:error, :invalid_vm_error} = SCStatus.new(vm_error: :UNKNOWN) - end - - test "new/1 when type is contract_error", %{} do - %SCStatus{type: :contract_error, value: 4_294_967_295} = - SCStatus.new(contract_error: 4_294_967_295) - end - - test "new/1 when type contract_error is incorrect" do - {:error, :invalid_uint32} = SCStatus.new(contract_error: :UNKNOWN) - end - - test "new/1 when type is host_auth_error", %{} do - %SCStatus{type: :host_auth_error, value: :HOST_AUTH_UNKNOWN_ERROR} = - SCStatus.new(host_auth_error: :HOST_AUTH_UNKNOWN_ERROR) - end - - test "new/1 when type host_auth_error is incorrect" do - {:error, :invalid_host_auth_error} = SCStatus.new(host_auth_error: :UNKNOWN) - end - - test "to_xdr when type is ok" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.Void{value: nil}, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_OK} - } = SCStatus.new(ok: nil) |> SCStatus.to_xdr() - end - - test "to_xdr when type is unknown_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCUnknownErrorCode{identifier: :UNKNOWN_ERROR_GENERAL}, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_UNKNOWN_ERROR} - } = SCStatus.new(unknown_error: :UNKNOWN_ERROR_GENERAL) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_value_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostValErrorCode{ - identifier: :HOST_VALUE_UNKNOWN_ERROR - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_VALUE_ERROR} - } = SCStatus.new(host_value_error: :HOST_VALUE_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_object_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostObjErrorCode{ - identifier: :HOST_OBJECT_UNKNOWN_ERROR - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_OBJECT_ERROR} - } = SCStatus.new(host_object_error: :HOST_OBJECT_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_function_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostFnErrorCode{identifier: :HOST_FN_UNKNOWN_ERROR}, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_FUNCTION_ERROR} - } = SCStatus.new(host_function_error: :HOST_FN_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_storage_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostStorageErrorCode{ - identifier: :HOST_STORAGE_UNKNOWN_ERROR - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_STORAGE_ERROR} - } = SCStatus.new(host_storage_error: :HOST_STORAGE_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_context_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostContextErrorCode{ - identifier: :HOST_CONTEXT_UNKNOWN_ERROR - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_CONTEXT_ERROR} - } = SCStatus.new(host_context_error: :HOST_CONTEXT_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end - - test "to_xdr when type is vm_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCVmErrorCode{identifier: :VM_UNKNOWN}, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_VM_ERROR} - } = SCStatus.new(vm_error: :VM_UNKNOWN) |> SCStatus.to_xdr() - end - - test "to_xdr when type is contract_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.UInt32{datum: 4_294_967_295}, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_CONTRACT_ERROR} - } = SCStatus.new(contract_error: 4_294_967_295) |> SCStatus.to_xdr() - end - - test "to_xdr when type is host_auth_error" do - %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCHostAuthErrorCode{ - identifier: :HOST_AUTH_UNKNOWN_ERROR - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_HOST_AUTH_ERROR} - } = SCStatus.new(host_auth_error: :HOST_AUTH_UNKNOWN_ERROR) |> SCStatus.to_xdr() - end -end diff --git a/test/tx_build/sc_val_test.exs b/test/tx_build/sc_val_test.exs index 4785ea15..928f7a46 100644 --- a/test/tx_build/sc_val_test.exs +++ b/test/tx_build/sc_val_test.exs @@ -1,9 +1,11 @@ defmodule Stellar.TxBuild.SCValTest do use ExUnit.Case + alias StellarBase.XDR.Int64 + alias Stellar.TxBuild.{ SCAddress, - SCStatus, + SCError, SCVal, SCMapEntry } @@ -53,11 +55,11 @@ defmodule Stellar.TxBuild.SCValTest do %{type: :symbol, value: "symbol"}, %{type: :vec, value: [sc_val]}, %{type: :map, value: [sc_map_entry]}, - %{type: :contract, value: :token}, - %{type: :contract, value: {:wasm_ref, "hash"}}, %{type: :address, value: sc_address}, - %{type: :ledger_key_contract, value: nil}, - %{type: :ledger_key_nonce, value: sc_address} + %{type: :ledger_key_contract_instance, value: nil}, + %{type: :ledger_key_nonce, value: 132_131}, + %{type: :contract_instance, value: :token}, + %{type: :contract_instance, value: {:wasm_ref, "hash"}} ] invalid_discriminants = [ @@ -77,22 +79,22 @@ defmodule Stellar.TxBuild.SCValTest do %{type: :symbol, value: :symbol}, %{type: :vec, value: [:sc_val]}, %{type: :map, value: [:sc_map_entry]}, - %{type: :contract, value: :invalid}, - %{type: :contract, value: {:wasm_ref, :invalid}}, %{type: :address, value: :invalid}, - %{type: :ledger_key_nonce, value: :invalid} + %{type: :ledger_key_nonce, value: :invalid}, + %{type: :contract_instance, value: :invalid} ] - sc_status_discriminants = [ - %{sc_status: SCStatus.new(ok: nil)}, - %{sc_status: SCStatus.new(unknown_error: :UNKNOWN_ERROR_GENERAL)}, - %{sc_status: SCStatus.new(host_value_error: :HOST_VALUE_UNKNOWN_ERROR)}, - %{sc_status: SCStatus.new(host_object_error: :HOST_OBJECT_UNKNOWN_ERROR)}, - %{sc_status: SCStatus.new(host_function_error: :HOST_FN_UNKNOWN_ERROR)}, - %{sc_status: SCStatus.new(host_storage_error: :HOST_STORAGE_UNKNOWN_ERROR)}, - %{sc_status: SCStatus.new(vm_error: :VM_UNKNOWN)}, - %{sc_status: SCStatus.new(contract_error: 4_294_967_295)}, - %{sc_status: SCStatus.new(host_auth_error: :HOST_AUTH_UNKNOWN_ERROR)} + sc_error_discriminants = [ + %{sc_error: SCError.new(contract: :arith_domain)}, + %{sc_error: SCError.new(wasm_vm: :index_bounds)}, + %{sc_error: SCError.new(context: :invalid_input)}, + %{sc_error: SCError.new(storage: :missing_value)}, + %{sc_error: SCError.new(object: :existing_value)}, + %{sc_error: SCError.new(crypto: :exceeded_limit)}, + %{sc_error: SCError.new(events: :invalid_action)}, + %{sc_error: SCError.new(budget: :internal_error)}, + %{sc_error: SCError.new(code: :unexpected_type)}, + %{sc_error: SCError.new(auth: :unexpected_size)} ] xdr_discriminants = [ @@ -104,15 +106,13 @@ defmodule Stellar.TxBuild.SCValTest do }, %{val_type: :SCV_VOID, module: %StellarBase.XDR.Void{value: nil}, type: :void, value: nil}, %{ - val_type: :SCV_STATUS, - module: %StellarBase.XDR.SCStatus{ - code: %StellarBase.XDR.SCUnknownErrorCode{ - identifier: :UNKNOWN_ERROR_GENERAL - }, - type: %StellarBase.XDR.SCStatusType{identifier: :SST_UNKNOWN_ERROR} + val_type: :SCV_ERROR, + module: %StellarBase.XDR.SCError{ + type: %StellarBase.XDR.SCErrorType{identifier: :SCE_CONTRACT}, + code: %StellarBase.XDR.SCErrorCode{identifier: :SCEC_ARITH_DOMAIN} }, - type: :status, - value: SCStatus.new(unknown_error: :UNKNOWN_ERROR_GENERAL) + type: :error, + value: SCError.new(contract: :arith_domain) }, %{val_type: :SCV_U32, module: %StellarBase.XDR.UInt32{datum: 123}, type: :u32, value: 123}, %{val_type: :SCV_I32, module: %StellarBase.XDR.Int32{datum: 123}, type: :i32, value: 123}, @@ -198,7 +198,7 @@ defmodule Stellar.TxBuild.SCValTest do val_type: :SCV_VEC, module: %StellarBase.XDR.OptionalSCVec{ sc_vec: %StellarBase.XDR.SCVec{ - sc_vals: [ + items: [ %StellarBase.XDR.SCVal{ value: %StellarBase.XDR.Int32{datum: 123}, type: %StellarBase.XDR.SCValType{identifier: :SCV_I32} @@ -219,7 +219,7 @@ defmodule Stellar.TxBuild.SCValTest do val_type: :SCV_MAP, module: %StellarBase.XDR.OptionalSCMap{ sc_map: %StellarBase.XDR.SCMap{ - scmap_entries: [ + items: [ %StellarBase.XDR.SCMapEntry{ key: %StellarBase.XDR.SCVal{ value: %StellarBase.XDR.SCSymbol{value: "sc_val_key"}, @@ -237,44 +237,50 @@ defmodule Stellar.TxBuild.SCValTest do value: [sc_map_entry] }, %{ - val_type: :SCV_CONTRACT_EXECUTABLE, - module: %StellarBase.XDR.SCContractExecutable{ - contract_executable: %StellarBase.XDR.Hash{value: "hash"}, - type: %StellarBase.XDR.SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_WASM_REF - } + val_type: :SCV_CONTRACT_INSTANCE, + module: %StellarBase.XDR.SCContractInstance{ + executable: %StellarBase.XDR.ContractExecutable{ + value: %StellarBase.XDR.Hash{value: "hash"}, + type: %StellarBase.XDR.ContractExecutableType{ + identifier: :CONTRACT_EXECUTABLE_WASM + } + }, + storage: %StellarBase.XDR.OptionalSCMap{sc_map: nil} }, - type: :contract, + type: :contract_instance, value: {:wasm_ref, "hash"} }, %{ - val_type: :SCV_CONTRACT_EXECUTABLE, - module: %StellarBase.XDR.SCContractExecutable{ - contract_executable: %StellarBase.XDR.Void{value: nil}, - type: %StellarBase.XDR.SCContractExecutableType{ - identifier: :SCCONTRACT_EXECUTABLE_TOKEN - } + val_type: :SCV_CONTRACT_INSTANCE, + module: %StellarBase.XDR.SCContractInstance{ + executable: %StellarBase.XDR.ContractExecutable{ + value: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.ContractExecutableType{ + identifier: :CONTRACT_EXECUTABLE_TOKEN + } + }, + storage: %StellarBase.XDR.OptionalSCMap{sc_map: nil} }, - type: :contract, + type: :contract_instance, value: :token }, %{val_type: :SCV_ADDRESS, module: sc_address_xdr, type: :address, value: sc_address}, %{ - val_type: :SCV_LEDGER_KEY_CONTRACT_EXECUTABLE, + val_type: :SCV_LEDGER_KEY_CONTRACT_INSTANCE, module: %StellarBase.XDR.Void{value: nil}, - type: :ledger_key_contract, + type: :ledger_key_contract_instance, value: nil }, %{ val_type: :SCV_LEDGER_KEY_NONCE, - module: %StellarBase.XDR.SCNonceKey{nonce_address: sc_address_xdr}, + module: %StellarBase.XDR.SCNonceKey{nonce: Int64.new(123_654)}, type: :ledger_key_nonce, - value: sc_address + value: 123_654 } ] %{ - sc_status_discriminants: sc_status_discriminants, + sc_error_discriminants: sc_error_discriminants, discriminants: discriminants, invalid_discriminants: invalid_discriminants, xdr_discriminants: xdr_discriminants @@ -298,9 +304,9 @@ defmodule Stellar.TxBuild.SCValTest do end end - test "new/1 when type is status", %{sc_status_discriminants: sc_status_discriminants} do - for %{sc_status: sc_status} <- sc_status_discriminants do - %SCVal{type: :status, value: ^sc_status} = SCVal.new(status: sc_status) + test "new/1 when type is error", %{sc_error_discriminants: sc_error_discriminants} do + for %{sc_error: sc_error} <- sc_error_discriminants do + %SCVal{type: :error, value: ^sc_error} = SCVal.new(error: sc_error) end end diff --git a/test/tx_build/soroban_address_credentials_test.exs b/test/tx_build/soroban_address_credentials_test.exs new file mode 100644 index 00000000..d2d54360 --- /dev/null +++ b/test/tx_build/soroban_address_credentials_test.exs @@ -0,0 +1,144 @@ +defmodule Stellar.TxBuild.SorobanAddressCredentialsTest do + use ExUnit.Case + + alias Stellar.TxBuild.SCVal + alias Stellar.TxBuild.SCVec + alias Stellar.TxBuild.SCAddress + alias Stellar.TxBuild.SorobanAddressCredentials + + setup do + address = SCAddress.new("GBNDWIM7DPYZJ2RLJ3IESXBIO4C2SVF6PWZXS3DLODJSBQWBMKY5U4M3") + signature_args = SCVec.new([SCVal.new(symbol: "dev")]) + nonce = 544_841 + signature_expiration_ledger = 106_977 + + xdr = %StellarBase.XDR.SorobanAddressCredentials{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<90, 59, 33, 159, 27, 241, 148, 234, 43, 78, 208, 73, 92, 40, 119, 5, 169, 84, + 190, 125, 179, 121, 108, 107, 112, 211, 32, 194, 193, 98, 177, 218>> + }, + type: %StellarBase.XDR.PublicKeyType{identifier: :PUBLIC_KEY_TYPE_ED25519} + } + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} + }, + nonce: %StellarBase.XDR.Int64{datum: 544_841}, + signature_expiration_ledger: %StellarBase.XDR.UInt32{datum: 106_977}, + signature_args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + } + + %{ + address: address, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger, + soroban_address_credentials: + SorobanAddressCredentials.new( + address: address, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + ), + xdr: xdr + } + end + + test "new/2", %{ + address: address, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + } do + %SorobanAddressCredentials{ + address: ^address, + signature_args: ^signature_args, + nonce: ^nonce, + signature_expiration_ledger: ^signature_expiration_ledger + } = + SorobanAddressCredentials.new( + address: address, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + ) + end + + test "new/2 with invalid address", %{ + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + } do + {:error, :invalid_address} = + SorobanAddressCredentials.new( + address: :invalid, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + ) + end + + test "new/2 with invalid signature_args", %{ + address: address, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + } do + {:error, :invalid_args} = + SorobanAddressCredentials.new( + address: address, + signature_args: :invalid, + nonce: nonce, + signature_expiration_ledger: signature_expiration_ledger + ) + end + + test "new/2 with invalid nonce", %{ + address: address, + signature_args: signature_args, + signature_expiration_ledger: signature_expiration_ledger + } do + {:error, :invalid_nonce} = + SorobanAddressCredentials.new( + address: address, + signature_args: signature_args, + nonce: :invalid, + signature_expiration_ledger: signature_expiration_ledger + ) + end + + test "new/2 with invalid signature_expiration_ledger", %{ + address: address, + signature_args: signature_args, + nonce: nonce + } do + {:error, :invalid_signature_expiration_ledger} = + SorobanAddressCredentials.new( + address: address, + signature_args: signature_args, + nonce: nonce, + signature_expiration_ledger: :invalid + ) + end + + test "new/2 with invalid args" do + {:error, :invalid_soroban_address_args} = SorobanAddressCredentials.new(:invalid) + end + + test "to_xdr/1", %{soroban_address_credentials: soroban_address_credentials, xdr: xdr} do + ^xdr = SorobanAddressCredentials.to_xdr(soroban_address_credentials) + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanAddressCredentials.to_xdr(:invalid) + end +end diff --git a/test/tx_build/soroban_authorization_entry_test.exs b/test/tx_build/soroban_authorization_entry_test.exs new file mode 100644 index 00000000..d15c7736 --- /dev/null +++ b/test/tx_build/soroban_authorization_entry_test.exs @@ -0,0 +1,109 @@ +defmodule Stellar.TxBuild.SorobanAuthorizationEntryTest do + use ExUnit.Case + + alias Stellar.TxBuild.SorobanAuthorizedInvocation + alias Stellar.TxBuild.SorobanAuthorizedFunction + alias Stellar.TxBuild.SorobanCredentials + alias Stellar.TxBuild.SorobanAuthorizedContractFunction + alias Stellar.TxBuild.SCVal + alias Stellar.TxBuild.SCVec + alias Stellar.TxBuild.SCAddress + alias Stellar.TxBuild.SorobanAuthorizationEntry + + setup do + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + + contract_address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + function_name = "hello" + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + + soroban_function = SorobanAuthorizedFunction.new(contract_fn: contract_fn) + + root_invocation = + SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + + credentials = SorobanCredentials.new(source_account: nil) + + soroban_auth_entry = + SorobanAuthorizationEntry.new(credentials: credentials, root_invocation: root_invocation) + + xdr = %StellarBase.XDR.SorobanAuthorizationEntry{ + credentials: %StellarBase.XDR.SorobanCredentials{ + value: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.SorobanCredentialsType{ + identifier: :SOROBAN_CREDENTIALS_SOURCE_ACCOUNT + } + }, + root_invocation: %StellarBase.XDR.SorobanAuthorizedInvocation{ + function: %StellarBase.XDR.SorobanAuthorizedFunction{ + value: %StellarBase.XDR.SorobanAuthorizedContractFunction{ + contract_address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.Hash{ + value: + <<103, 224, 63, 135, 151, 127, 210, 146, 103, 195, 188, 38, 35, 58, 109, 10, + 245, 168, 95, 73, 157, 243, 180, 36, 28, 222, 188, 164, 3, 159, 98, 56>> + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_CONTRACT} + }, + function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, + args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + }, + type: %StellarBase.XDR.SorobanAuthorizedFunctionType{ + identifier: :SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN + } + }, + sub_invocations: %StellarBase.XDR.SorobanAuthorizedInvocationList{items: []} + } + } + + %{ + credentials: credentials, + root_invocation: root_invocation, + soroban_auth_entry: soroban_auth_entry, + xdr: xdr + } + end + + test "new/2", %{credentials: credentials, root_invocation: root_invocation} do + %SorobanAuthorizationEntry{ + credentials: ^credentials, + root_invocation: ^root_invocation + } = SorobanAuthorizationEntry.new(credentials: credentials, root_invocation: root_invocation) + end + + test "new/2 with invalid credentials", %{root_invocation: root_invocation} do + {:error, :invalid_credentials} = + SorobanAuthorizationEntry.new(credentials: :invalid, root_invocation: root_invocation) + end + + test "new/2 with invalid root_invocation", %{credentials: credentials} do + {:error, :invalid_root_invocation} = + SorobanAuthorizationEntry.new(credentials: credentials, root_invocation: :invalid) + end + + test "new/2 with invalid args" do + {:error, :invalid_auth_entry_args} = SorobanAuthorizationEntry.new(:invalid) + end + + test "to_xdr/1", %{soroban_auth_entry: soroban_auth_entry, xdr: xdr} do + ^xdr = SorobanAuthorizationEntry.to_xdr(soroban_auth_entry) + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanAuthorizationEntry.to_xdr(:invalid) + end +end diff --git a/test/tx_build/soroban_authorized_contract_function_test.exs b/test/tx_build/soroban_authorized_contract_function_test.exs new file mode 100644 index 00000000..b5a4c3d8 --- /dev/null +++ b/test/tx_build/soroban_authorized_contract_function_test.exs @@ -0,0 +1,117 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedContractFunctionTest do + use ExUnit.Case + + alias Stellar.TxBuild.SCAddress + alias Stellar.TxBuild.SCVec + alias Stellar.TxBuild.SCVal + alias Stellar.TxBuild.SorobanAuthorizedContractFunction + + setup do + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + + contract_address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + function_name = "hello" + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + + xdr = %StellarBase.XDR.SorobanAuthorizedContractFunction{ + contract_address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.Hash{ + value: + <<103, 224, 63, 135, 151, 127, 210, 146, 103, 195, 188, 38, 35, 58, 109, 10, 245, 168, + 95, 73, 157, 243, 180, 36, 28, 222, 188, 164, 3, 159, 98, 56>> + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_CONTRACT} + }, + function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, + args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + } + + %{ + contract_address: contract_address, + function_name: function_name, + fn_args: fn_args, + contract_fn: contract_fn, + xdr: xdr + } + end + + test "new/2", %{ + contract_address: contract_address, + function_name: function_name, + fn_args: fn_args + } do + %SorobanAuthorizedContractFunction{ + contract_address: ^contract_address, + function_name: ^function_name, + args: ^fn_args + } = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + end + + test "new/2 with invalid contract_address", %{ + function_name: function_name, + fn_args: fn_args + } do + {:error, :invalid_address} = + SorobanAuthorizedContractFunction.new( + contract_address: :invalid, + function_name: function_name, + args: fn_args + ) + end + + test "new/2 with invalid function name", %{ + contract_address: contract_address, + fn_args: fn_args + } do + {:error, :invalid_function_name} = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: :invalid, + args: fn_args + ) + end + + test "new/2 with invalid function args", %{ + contract_address: contract_address, + function_name: function_name + } do + {:error, :invalid_args} = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: :invalid + ) + end + + test "new/2 with invalid args" do + {:error, :invalid_soroban_auth_contract_function_args} = + SorobanAuthorizedContractFunction.new(:invalid) + end + + test "to_xdr/1", %{contract_fn: contract_fn, xdr: xdr} do + ^xdr = SorobanAuthorizedContractFunction.to_xdr(contract_fn) + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanAuthorizedContractFunction.to_xdr(:invalid) + end +end diff --git a/test/tx_build/soroban_authorized_function_test.exs b/test/tx_build/soroban_authorized_function_test.exs new file mode 100644 index 00000000..af8b15f5 --- /dev/null +++ b/test/tx_build/soroban_authorized_function_test.exs @@ -0,0 +1,180 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedFunctionTest do + use ExUnit.Case + + alias Stellar.TxBuild.{ + SCVec, + SCVal, + CreateContractArgs, + ContractIDPreimage, + ContractIDPreimageFromAddress, + SCAddress, + ContractExecutable, + SorobanAuthorizedContractFunction, + SorobanAuthorizedFunction + } + + setup do + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + + contract_address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + function_name = "hello" + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + + wasm_id = + <<86, 32, 6, 9, 172, 4, 212, 185, 249, 87, 184, 164, 58, 34, 167, 183, 226, 117, 205, 116, + 11, 130, 119, 172, 224, 51, 12, 148, 90, 251, 17, 12>> + + contract_executable = ContractExecutable.new(wasm_ref: wasm_id) + sc_address = SCAddress.new("GARVXS4KWSI6UQWZL2AAIB2KD4MAXG27YOE6IE64THZRSASAVR3ZPSUN") + # :crypto.strong_rand_bytes(32) + salt = + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, 67, 167, 216, + 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + + from_address = ContractIDPreimageFromAddress.new(address: sc_address, salt: salt) + contract_id_preimage = ContractIDPreimage.new(from_address: from_address) + + create_contract_args = + CreateContractArgs.new( + contract_id_preimage: contract_id_preimage, + contract_executable: contract_executable + ) + + discriminants = [ + %{type: :contract_fn, value: contract_fn}, + %{type: :create_contract_host_fn, value: create_contract_args} + ] + + invalid_discriminants = [ + %{type: :contract_fn, value: :invalid}, + %{type: :create_contract_host_fn, value: :invalid} + ] + + xdr_discriminants = [ + %{ + xdr: %StellarBase.XDR.SorobanAuthorizedFunction{ + value: %StellarBase.XDR.SorobanAuthorizedContractFunction{ + contract_address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.Hash{ + value: + <<103, 224, 63, 135, 151, 127, 210, 146, 103, 195, 188, 38, 35, 58, 109, 10, + 245, 168, 95, 73, 157, 243, 180, 36, 28, 222, 188, 164, 3, 159, 98, 56>> + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_CONTRACT} + }, + function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, + args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + }, + type: %StellarBase.XDR.SorobanAuthorizedFunctionType{ + identifier: :SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN + } + }, + type: :contract_fn, + value: contract_fn + }, + %{ + xdr: %StellarBase.XDR.SorobanAuthorizedFunction{ + value: %StellarBase.XDR.CreateContractArgs{ + contract_id_preimage: %StellarBase.XDR.ContractIDPreimage{ + value: %StellarBase.XDR.ContractIDPreimageFromAddress{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<35, 91, 203, 138, 180, 145, 234, 66, 217, 94, 128, 4, 7, 74, 31, 24, + 11, 155, 95, 195, 137, 228, 19, 220, 153, 243, 25, 2, 64, 172, 119, + 151>> + }, + type: %StellarBase.XDR.PublicKeyType{ + identifier: :PUBLIC_KEY_TYPE_ED25519 + } + } + }, + type: %StellarBase.XDR.SCAddressType{ + identifier: :SC_ADDRESS_TYPE_ACCOUNT + } + }, + salt: %StellarBase.XDR.UInt256{ + datum: + <<142, 226, 180, 159, 151, 224, 223, 135, 33, 210, 154, 238, 13, 199, 60, 77, + 67, 167, 216, 125, 245, 241, 237, 114, 207, 74, 226, 98, 166, 200, 43, 89>> + } + }, + type: %StellarBase.XDR.ContractIDPreimageType{ + identifier: :CONTRACT_ID_PREIMAGE_FROM_ADDRESS + } + }, + executable: %StellarBase.XDR.ContractExecutable{ + value: %StellarBase.XDR.Hash{ + value: + <<86, 32, 6, 9, 172, 4, 212, 185, 249, 87, 184, 164, 58, 34, 167, 183, 226, 117, + 205, 116, 11, 130, 119, 172, 224, 51, 12, 148, 90, 251, 17, 12>> + }, + type: %StellarBase.XDR.ContractExecutableType{ + identifier: :CONTRACT_EXECUTABLE_WASM + } + } + }, + type: %StellarBase.XDR.SorobanAuthorizedFunctionType{ + identifier: :SOROBAN_AUTHORIZED_FUNCTION_TYPE_CREATE_CONTRACT_HOST_FN + } + }, + type: :create_contract_host_fn, + value: create_contract_args + } + ] + + %{ + discriminants: discriminants, + invalid_discriminants: invalid_discriminants, + xdr_discriminants: xdr_discriminants + } + end + + test "new/1", %{discriminants: discriminants} do + for %{type: type, value: value} <- discriminants do + %SorobanAuthorizedFunction{ + type: ^type, + value: ^value + } = SorobanAuthorizedFunction.new([{type, value}]) + end + end + + test "new/1 with invalid values", %{invalid_discriminants: invalid_discriminants} do + for %{type: type, value: value} <- invalid_discriminants do + error = :"invalid_#{type}" + {:error, ^error} = SorobanAuthorizedFunction.new([{type, value}]) + end + end + + test "new/1 with invalid args" do + {:error, :invalid_soroban_auth_function} = SorobanAuthorizedFunction.new(:invalid) + end + + test "to_xdr/1", %{xdr_discriminants: xdr_discriminants} do + for %{xdr: xdr, type: type, value: value} <- xdr_discriminants do + ^xdr = + SorobanAuthorizedFunction.new([{type, value}]) + |> SorobanAuthorizedFunction.to_xdr() + end + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanAuthorizedFunction.to_xdr(%{}) + end +end diff --git a/test/tx_build/soroban_authorized_invocation_test.exs b/test/tx_build/soroban_authorized_invocation_test.exs new file mode 100644 index 00000000..4d812143 --- /dev/null +++ b/test/tx_build/soroban_authorized_invocation_test.exs @@ -0,0 +1,112 @@ +defmodule Stellar.TxBuild.SorobanAuthorizedInvocationTest do + use ExUnit.Case + + alias Stellar.TxBuild.{ + SCVec, + SCVal, + SCAddress, + SorobanAuthorizedContractFunction, + SorobanAuthorizedFunction, + SorobanAuthorizedInvocation + } + + setup do + fn_args = SCVec.new([SCVal.new(symbol: "dev")]) + + contract_address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + + function_name = "hello" + + contract_fn = + SorobanAuthorizedContractFunction.new( + contract_address: contract_address, + function_name: function_name, + args: fn_args + ) + + soroban_function = SorobanAuthorizedFunction.new(contract_fn: contract_fn) + + sub_invocations = [ + SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + ] + + auth_invocation_xdr = %StellarBase.XDR.SorobanAuthorizedInvocation{ + function: %StellarBase.XDR.SorobanAuthorizedFunction{ + value: %StellarBase.XDR.SorobanAuthorizedContractFunction{ + contract_address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.Hash{ + value: + <<103, 224, 63, 135, 151, 127, 210, 146, 103, 195, 188, 38, 35, 58, 109, 10, 245, + 168, 95, 73, 157, 243, 180, 36, 28, 222, 188, 164, 3, 159, 98, 56>> + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_CONTRACT} + }, + function_name: %StellarBase.XDR.SCSymbol{value: "hello"}, + args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + }, + type: %StellarBase.XDR.SorobanAuthorizedFunctionType{ + identifier: :SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN + } + }, + sub_invocations: %StellarBase.XDR.SorobanAuthorizedInvocationList{items: []} + } + + %{ + soroban_function: soroban_function, + sub_invocations: sub_invocations, + auth_invocation_xdr: auth_invocation_xdr + } + end + + test "new/2", %{soroban_function: soroban_function} do + %SorobanAuthorizedInvocation{ + function: ^soroban_function, + sub_invocations: [] + } = SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + end + + test "new/2 with sub invocations", %{ + soroban_function: soroban_function, + sub_invocations: sub_invocations + } do + %SorobanAuthorizedInvocation{ + function: ^soroban_function, + sub_invocations: ^sub_invocations + } = + SorobanAuthorizedInvocation.new( + function: soroban_function, + sub_invocations: sub_invocations + ) + end + + test "new/2 invalid function" do + {:error, :invalid_function} = + SorobanAuthorizedInvocation.new(function: :invalid, sub_invocations: []) + end + + test "new/2 invalid sub_invocations", %{soroban_function: soroban_function} do + {:error, :invalid_sub_invocations} = + SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: [:invalid]) + end + + test "new/2 invalid args" do + {:error, :invalid_soroban_auth_invocation} = SorobanAuthorizedInvocation.new(:invalid) + end + + test "to_xdr/1", %{soroban_function: soroban_function, auth_invocation_xdr: auth_invocation_xdr} do + ^auth_invocation_xdr = + SorobanAuthorizedInvocation.new(function: soroban_function, sub_invocations: []) + |> SorobanAuthorizedInvocation.to_xdr() + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanAuthorizedInvocation.to_xdr(:invalid) + end +end diff --git a/test/tx_build/soroban_credentials_test.exs b/test/tx_build/soroban_credentials_test.exs new file mode 100644 index 00000000..e035824f --- /dev/null +++ b/test/tx_build/soroban_credentials_test.exs @@ -0,0 +1,120 @@ +defmodule Stellar.TxBuild.SorobanCredentialsTest do + use ExUnit.Case + + alias Stellar.TxBuild.{ + SCVec, + SCVal, + SorobanCredentials, + SCAddress, + SorobanAddressCredentials + } + + setup do + address = SCAddress.new("GBNDWIM7DPYZJ2RLJ3IESXBIO4C2SVF6PWZXS3DLODJSBQWBMKY5U4M3") + signature_args = SCVec.new([SCVal.new(symbol: "dev")]) + + soroban_address_credentials = + SorobanAddressCredentials.new( + address: address, + nonce: 123_135, + signature_expiration_ledger: 123_515, + signature_args: signature_args + ) + + discriminants = [ + %{type: :source_account, value: nil}, + %{type: :address, value: soroban_address_credentials} + ] + + invalid_discriminants = [ + %{type: :source_account, value: :invalid}, + %{type: :address, value: :invalid} + ] + + xdr_discriminants = [ + %{ + xdr: %StellarBase.XDR.SorobanCredentials{ + value: %StellarBase.XDR.Void{value: nil}, + type: %StellarBase.XDR.SorobanCredentialsType{ + identifier: :SOROBAN_CREDENTIALS_SOURCE_ACCOUNT + } + }, + type: :source_account, + value: nil + }, + %{ + xdr: %StellarBase.XDR.SorobanCredentials{ + value: %StellarBase.XDR.SorobanAddressCredentials{ + address: %StellarBase.XDR.SCAddress{ + sc_address: %StellarBase.XDR.AccountID{ + account_id: %StellarBase.XDR.PublicKey{ + public_key: %StellarBase.XDR.UInt256{ + datum: + <<90, 59, 33, 159, 27, 241, 148, 234, 43, 78, 208, 73, 92, 40, 119, 5, 169, + 84, 190, 125, 179, 121, 108, 107, 112, 211, 32, 194, 193, 98, 177, 218>> + }, + type: %StellarBase.XDR.PublicKeyType{ + identifier: :PUBLIC_KEY_TYPE_ED25519 + } + } + }, + type: %StellarBase.XDR.SCAddressType{identifier: :SC_ADDRESS_TYPE_ACCOUNT} + }, + nonce: %StellarBase.XDR.Int64{datum: 123_135}, + signature_expiration_ledger: %StellarBase.XDR.UInt32{datum: 123_515}, + signature_args: %StellarBase.XDR.SCVec{ + items: [ + %StellarBase.XDR.SCVal{ + value: %StellarBase.XDR.SCSymbol{value: "dev"}, + type: %StellarBase.XDR.SCValType{identifier: :SCV_SYMBOL} + } + ] + } + }, + type: %StellarBase.XDR.SorobanCredentialsType{ + identifier: :SOROBAN_CREDENTIALS_ADDRESS + } + }, + type: :address, + value: soroban_address_credentials + } + ] + + %{ + soroban_address_credentials: soroban_address_credentials, + discriminants: discriminants, + invalid_discriminants: invalid_discriminants, + xdr_discriminants: xdr_discriminants + } + end + + test "new/2", %{discriminants: discriminants} do + for %{type: type, value: value} <- discriminants do + %SorobanCredentials{ + type: ^type, + value: ^value + } = SorobanCredentials.new([{type, value}]) + end + end + + test "new/2 with invalid values", %{invalid_discriminants: invalid_discriminants} do + for %{type: type, value: value} <- invalid_discriminants do + error = :"invalid_#{type}" + {:error, ^error} = SorobanCredentials.new([{type, value}]) + end + end + + test "new/2 with invalid args" do + {:error, :invalid_soroban_credential} = SorobanCredentials.new(:invalid) + end + + test "to_xdr/1", %{xdr_discriminants: xdr_discriminants} do + for %{xdr: xdr, type: type, value: value} <- xdr_discriminants do + ^xdr = SorobanCredentials.new([{type, value}]) |> SorobanCredentials.to_xdr() + end + end + + test "to_xdr/1 error" do + {:error, :invalid_struct} = SorobanCredentials.to_xdr(%{}) + end +end diff --git a/test/tx_build/validations_test.exs b/test/tx_build/validations_test.exs index 58345bee..24e9bf25 100644 --- a/test/tx_build/validations_test.exs +++ b/test/tx_build/validations_test.exs @@ -1,17 +1,17 @@ defmodule Stellar.TxBuild.ValidationsTest do use ExUnit.Case + alias Stellar.TxBuild.SCVec + alias Stellar.TxBuild.{ Account, AccountID, - AddressWithNonce, Amount, Asset, AssetsPath, ClaimableBalanceID, Validations, OptionalAccountID, - OptionalAddressWithNonce, SCAddress, SequenceNumber, PoolID, @@ -140,18 +140,6 @@ defmodule Stellar.TxBuild.ValidationsTest do Validations.validate_pool_id({:liquidity_pool_id, "ABC"}) end - test "validate_optional_address_with_nonce/1", %{account_id: account_id} do - address_with_nonce = AddressWithNonce.new(address: SCAddress.new(account_id), nonce: 123) - - {:ok, %OptionalAddressWithNonce{}} = - Validations.validate_optional_address_with_nonce({:address_with_nonce, address_with_nonce}) - end - - test "validate_optional_address_with_nonce/1 error" do - {:error, :invalid_address_with_nonce} = - Validations.validate_optional_address_with_nonce({:address_with_nonce, "invalid"}) - end - test "validate_sequence_number/1" do seq_number = SequenceNumber.new() {:ok, ^seq_number} = Validations.validate_sequence_number({:seq_number, seq_number}) @@ -160,4 +148,22 @@ defmodule Stellar.TxBuild.ValidationsTest do test "validate_sequence_number/1 error" do {:error, :invalid_seq_number} = Validations.validate_sequence_number({:seq_number, "invalid"}) end + + test "validate_address" do + address = SCAddress.new("CBT6AP4HS575FETHYO6CMIZ2NUFPLKC7JGO7HNBEDTPLZJADT5RDRZP4") + {:ok, ^address} = Validations.validate_address(address) + end + + test "validate_address error" do + {:error, :invalid_address} = Validations.validate_address(:invalid) + end + + test "validate_vec" do + vec = SCVec.new([]) + {:ok, ^vec} = Validations.validate_vec(vec) + end + + test "validate_vec error" do + {:error, :invalid_args} = Validations.validate_vec(:invalid) + end end