From d416eb4db7e32557c1203d48a4d23c3fc8882585 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:29:51 +0545 Subject: [PATCH 1/8] certificate decoder --- lib/sutra/cardano/transaction/certificate.ex | 281 +++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 lib/sutra/cardano/transaction/certificate.ex diff --git a/lib/sutra/cardano/transaction/certificate.ex b/lib/sutra/cardano/transaction/certificate.ex new file mode 100644 index 0000000..c434f77 --- /dev/null +++ b/lib/sutra/cardano/transaction/certificate.ex @@ -0,0 +1,281 @@ +defmodule Sutra.Cardano.Transaction.Certificate do + @moduledoc """ + Cardano Transaction Certificate + """ + + alias Sutra.Cardano.Asset + alias Sutra.Cardano.Transaction.Certificate.PoolRegistration + alias Sutra.Cardano.Transaction.Certificate.PoolRetirement + alias Sutra.Cardano.Transaction.Certificate.Drep + alias Sutra.Cardano.Address + alias Sutra.Cardano.Common.PoolRelay + alias Sutra.Cardano.Transaction.Certificate.StakeRegistration + alias Sutra.Cardano.Address.Credential + + import Sutra.Data.Cbor, only: [extract_value!: 1] + import Sutra.Utils, only: [maybe: 3] + + @type drep() :: %{ + drep_type: Address.credential_type() | nil, + drep_value: String.t() + } + + use TypedStruct + + ## (0, stake_credential) -- will be deprecated in future era + typedstruct(module: StakeRegistration) do + field(:stake_credential, Credential.t(), enforce: true) + end + + ## (1, stake_credential) -- will be deprecated in future era + typedstruct(module: StakeDeRegistration) do + field(:stake_credential, Credential.t(), enforce: true) + end + + ## (2, stake_credential, pool_keyhash) + typedstruct(module: StakeDelegation) do + field(:stake_credential, Credential.t(), enforce: true) + field(:pool_keyhash, :string, enforce: true) + end + + ## (3, pool_params) + typedstruct(module: PoolRegistration) do + field(:pool_key_hash, :string, enforce: true) + field(:vrf_key_hash, :string, enforce: true) + field(:pledge, :integer, enforce: true) + field(:cost, :integer, enforce: true) + field(:margin, :integer, enforce: true) + field(:reward_account, :string, enforce: true) + field(:owners, [:string], enforce: true) + field(:relays, [PoolRelay.t()], enforce: true) + field(:metadata, %{url: :string, hash: :string}) + end + + ## (4, pool_keyhash, epoch_no) + typedstruct(module: PoolRetirement) do + field(:pool_keyhash, :string, enforce: true) + field(:epoch_no, :integer, enforce: true) + end + + ## (7, stake_credential, coin) + typedstruct(module: RegisterCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:coin, :integer, enforce: true) + end + + ## (8, stake_credential, coin) + typedstruct(module: UnRegisterCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:coin, :integer, enforce: true) + end + + ## vote_deleg_cert (9, stake_credential, drep) + typedstruct(module: VoteDelegCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:drep, Drep.t(), enforce: true) + end + + ## (10, stake_credential, pool_keyhash, drep) + typedstruct(module: StakeVoteDelegCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:pool_keyhash, :string, enforce: true) + field(:drep, Drep.t(), enforce: true) + end + + ## (11, stake_credential, pool_keyhash, coin) + typedstruct(module: StakeRegDelegCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:pool_keyhash, :string, enforce: true) + field(:deposit, Asset.t(), enforce: true) + end + + ## (12, stake_credential, drep, coin) + typedstruct(module: VoteRegDelegCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:drep, :string, enforce: true) + field(:deposit, :integer, enforce: true) + end + + ## (13, stake_credential, pool_keyhash, drep, coin) + typedstruct(module: StakeVoteRegDelegCert) do + field(:stake_credential, Credential.t(), enforce: true) + field(:pool_keyhash, :string, enforce: true) + field(:drep, :string, enforce: true) + field(:deposit, Asset.t(), enforce: true) + end + + ## (14, committee_cold_credential, committee_hot_credential) + typedstruct(module: AuthCommitteeHotCert) do + field(:committee_cold_credential, Credential.t(), enforce: true) + field(:committee_hot_credential, Credential.t(), enforce: true) + end + + ## (15, committee_cold_credential, anchor / nil) + typedstruct(module: ResignCommitteeColdCert) do + field(:committee_cold_credential, Credential.t(), enforce: true) + field(:anchor, :string) + end + + ## (16, drep_credential, coin, anchor / nil) + typedstruct(module: RegDrepCert) do + field(:drep_credential, Credential.t(), enforce: true) + field(:deposit, Asset.t(), enforce: true) + field(:anchor, %{url: :string, hash: :string}) + end + + ## (17, drep_credential, coin) + typedstruct(module: UnRegDrepCert) do + field(:drep_credential, Credential.t(), enforce: true) + field(:deposit, Asset.t(), enforce: true) + end + + ## (18, drep_credential, anchor / nil) + typedstruct(module: UpdateDrepCert) do + field(:drep_credential, Credential.t(), enforce: true) + field(:anchor, %{url: :string, hash: :string}) + end + + typedstruct(module: Drep) do + field(:drep_type, Address.credential_type() | nil | pos_integer()) + field(:drep_value, :string) + end + + def decode([0, stake_credential]) do + %StakeRegistration{stake_credential: parse_credential(stake_credential)} + end + + def decode([1, stake_credential]) do + %StakeDeRegistration{stake_credential: parse_credential(stake_credential)} + end + + def decode([2, stake_cred, pool_key]) do + %StakeDelegation{ + stake_credential: parse_credential(stake_cred), + pool_keyhash: extract_value!(pool_key) + } + end + + def decode([ + 3, + pool_key, + vrf, + pledge, + cost, + %CBOR.Tag{value: [n, d]}, + reward_accont, + owners, + relays, + pool_metadata + ]) do + %PoolRegistration{ + pool_key_hash: extract_value!(pool_key), + vrf_key_hash: extract_value!(vrf), + pledge: Asset.lovelace_of(pledge), + cost: Asset.lovelace_of(cost), + margin: n / d, + reward_account: extract_value!(reward_accont), + owners: Enum.map(owners, &extract_value!/1), + relays: Enum.map(relays, &PoolRelay.decode/1), + metadata: maybe(pool_metadata, nil, fn [u, h] -> %{url: u, hash: h} end) + } + end + + def decode([4, %CBOR.Tag{value: pool_keyhash}, epoch_no]) do + %PoolRetirement{pool_keyhash: pool_keyhash, epoch_no: epoch_no} + end + + def decode([7, [cred_type, %CBOR.Tag{value: stake_credential}], coin]) do + credential_type = if cred_type == 0, do: :vkey, else: :script + + %RegisterCert{ + stake_credential: %Credential{credential_type: credential_type, hash: stake_credential}, + coin: coin + } + end + + def decode([8, stake_credential, coin]) do + %UnRegisterCert{ + stake_credential: parse_credential(stake_credential), + coin: Asset.lovelace_of(coin) + } + end + + def decode([9, stake_credential, drep]) do + %VoteDelegCert{ + stake_credential: parse_credential(stake_credential), + drep: decode_drep(drep) + } + end + + def decode([10, stake_cred, pool_key_hash, drep]) do + %StakeVoteDelegCert{ + stake_credential: parse_credential(stake_cred), + pool_keyhash: extract_value!(pool_key_hash), + drep: decode_drep(drep) + } + end + + def decode([11, stake_cred, pool_key_hash, coin]) do + %StakeRegDelegCert{ + stake_credential: parse_credential(stake_cred), + pool_keyhash: extract_value!(pool_key_hash), + deposit: Asset.lovelace_of(coin) + } + end + + def decode([13, stake_cred, pool_key_hash, drep, coin]) do + %StakeVoteRegDelegCert{ + stake_credential: parse_credential(stake_cred), + pool_keyhash: extract_value!(pool_key_hash), + drep: decode_drep(drep), + deposit: Asset.lovelace_of(coin) + } + end + + def decode([14, cold_cred, hot_cred]) do + %AuthCommitteeHotCert{ + committee_cold_credential: parse_credential(cold_cred), + committee_hot_credential: parse_credential(hot_cred) + } + end + + def decode([12, stake_cred, drep, coin]) do + %VoteRegDelegCert{ + stake_credential: parse_credential(stake_cred), + drep: decode_drep(drep), + deposit: Asset.lovelace_of(coin) + } + end + + def decode([16, drep_cred, coin, anchor]) do + %RegDrepCert{ + drep_credential: parse_credential(drep_cred), + deposit: Asset.lovelace_of(coin), + anchor: maybe(anchor, nil, fn [u, h] -> %{url: u, hash: h} end) + } + end + + def decode([17, drep_cred, coin]) do + %UnRegDrepCert{ + drep_credential: parse_credential(drep_cred), + deposit: Asset.lovelace_of(coin) + } + end + + def decode([18, drep_cred, anchor]) do + %UpdateDrepCert{ + drep_credential: parse_credential(drep_cred), + anchor: maybe(anchor, nil, fn [u, h] -> %{url: u, hash: h} end) + } + end + + defp parse_credential([cred_type, %CBOR.Tag{value: stake_credential}]) do + credential_type = if cred_type == 0, do: :vkey, else: :script + %Credential{credential_type: credential_type, hash: stake_credential} + end + + def decode_drep([0, v]), do: %Drep{drep_type: :vkey, drep_value: extract_value!(v)} + def decode_drep([1, v]), do: %Drep{drep_type: :script, drep_value: extract_value!(v)} + def decode_drep([n | _]) when is_integer(n), do: %Drep{drep_type: n} + def decode_drep(_), do: nil +end From 6ab6012fdc6ee5a620b99d76b89c6ada2b4f6d84 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:30:30 +0545 Subject: [PATCH 2/8] witness set decoder --- lib/sutra/cardano/transaction/witness.ex | 113 +++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 lib/sutra/cardano/transaction/witness.ex diff --git a/lib/sutra/cardano/transaction/witness.ex b/lib/sutra/cardano/transaction/witness.ex new file mode 100644 index 0000000..ff92d91 --- /dev/null +++ b/lib/sutra/cardano/transaction/witness.ex @@ -0,0 +1,113 @@ +defmodule Sutra.Cardano.Transaction.Witness do + @moduledoc """ + Cardano Transaction Witness + """ + + use TypedStruct + + alias Sutra.Cardano.Script.NativeScript + alias Sutra.Data.Plutus + alias Sutra.Utils + + import Sutra.Data.Cbor, only: [extract_value!: 1] + + @type t() :: __MODULE__.VkeyWitness.t() | __MODULE__.Redeemer.t() + + typedstruct(module: VkeyWitness) do + field(:vkey, String.t()) + field(:signature, String.t()) + end + + typedstruct(module: Redeemer) do + @type redeemer_tag() :: :spend | :mint | :cert | :reward | :vote | :propose + + field(:tag, redeemer_tag()) + field(:index, integer()) + field(:data, Sutra.Data.Plutus.t()) + field(:exunits, {integer(), integer()}) + field(:is_legacy, boolean(), default: false) + + def decode_tag!(0), do: :spend + def decode_tag!(1), do: :mint + def decode_tag!(2), do: :cert + def decode_tag!(3), do: :reward + def decode_tag!(4), do: :vote + def decode_tag!(5), do: :propose + def decode_tag!(n), do: raise("Invalid redeemer tag: #{n}") + end + + typedstruct(module: ScriptWitness) do + @type script_type() :: + :native_script + | :plutus_v1 + | :plutus_v2 + | :plutus_v3 + + field(:script_type, script_type()) + field(:data, String.t()) + + def decode_script_type!(1), do: :native + def decode_script_type!(3), do: :plutus_v1 + def decode_script_type!(6), do: :plutus_v2 + def decode_script_type!(7), do: :plutus_v3 + end + + def decode({0, %CBOR.Tag{tag: 258, value: vkey_witnesses}}), do: decode({0, vkey_witnesses}) + + def decode({0, vkey_witnesses}) do + Enum.map(vkey_witnesses, fn [vkey, signature] -> + %VkeyWitness{vkey: extract_value!(vkey), signature: extract_value!(signature)} + end) + end + + def decode({1, native_scripts}) do + [ + %ScriptWitness{ + script_type: :native, + data: Enum.map(extract_value!(native_scripts), &NativeScript.from_witness_set/1) + } + ] + end + + def decode({script_type, script_value}) when script_type in [3, 6, 7] do + [ + %ScriptWitness{ + script_type: ScriptWitness.decode_script_type!(script_type), + data: extract_value!(script_value) |> Enum.map(&extract_value!/1) + } + ] + end + + def decode({5, redeemer_witnesses}) when is_map(redeemer_witnesses) do + Enum.map(redeemer_witnesses, fn {[tag, index], [data, [mem, exec]]} -> + %Redeemer{ + tag: __MODULE__.Redeemer.decode_tag!(tag), + index: index, + data: Plutus.decode(data) |> Utils.ok_or(data), + exunits: {mem, exec}, + is_legacy: true + } + end) + end + + def decode({5, redeemer_witnesses}) when is_list(redeemer_witnesses) do + Enum.map(redeemer_witnesses, fn [tag, index, data, [mem, exec]] -> + %Redeemer{ + tag: __MODULE__.Redeemer.decode_tag!(tag), + index: index, + data: Plutus.decode(data) |> Utils.ok_or(data), + exunits: {mem, exec}, + is_legacy: true + } + end) + end + + def decode({red_type, redeemer_info}) do + raise """ + Not Implemented Redeemer Type: \n #{inspect(red_type)} + + Redeemer Info: \n #{inspect(redeemer_info)} + + """ + end +end From 1d7a3dccc53ff6a572c30a0ff661d018a9840bb1 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:31:58 +0545 Subject: [PATCH 3/8] native script witness --- lib/sutra/cardano/script/native_script.ex | 65 +++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 lib/sutra/cardano/script/native_script.ex diff --git a/lib/sutra/cardano/script/native_script.ex b/lib/sutra/cardano/script/native_script.ex new file mode 100644 index 0000000..c63f586 --- /dev/null +++ b/lib/sutra/cardano/script/native_script.ex @@ -0,0 +1,65 @@ +defmodule Sutra.Cardano.Script.NativeScript do + @moduledoc """ + Cardano Native Script + """ + alias Sutra.Cardano.Script.NativeScript + + @type t() :: + ScriptPubkey.t() + | ScriptAll.t() + | ScriptAny.t() + | ScriptNOfK.t() + | ScriptInvalidBefore.t() + | ScriptInvalidHereafter.t() + + use TypedStruct + + typedstruct(module: ScriptPubkey) do + field(:pubkey_hash, String.t()) + end + + typedstruct(module: ScriptAll) do + field(:scripts, [String.t()]) + end + + typedstruct(module: ScriptAny) do + field(:scripts, [String.t()]) + end + + typedstruct(module: ScriptNOfK) do + field(:n, integer()) + field(:scripts, [NativeScript.t()]) + end + + typedstruct(module: ScriptInvalidBefore) do + field(:slot, integer()) + end + + typedstruct(module: ScriptInvalidHereafter) do + field(:slot, integer()) + end + + def from_witness_set([0, pubkey]) do + %ScriptPubkey{pubkey_hash: pubkey} + end + + def from_witness_set([1, native_scripts]) do + %ScriptAll{scripts: Enum.map(native_scripts, &from_witness_set/1)} + end + + def from_witness_set([2, native_scripts]) do + %ScriptAny{scripts: Enum.map(native_scripts, &from_witness_set/1)} + end + + def from_witness_set([3, n, native_scripts]) do + %ScriptNOfK{n: n, scripts: Enum.map(native_scripts, &from_witness_set/1)} + end + + def from_witness_set([4, slot]) do + %ScriptInvalidBefore{slot: slot} + end + + def from_witness_set([5, slot]) do + %ScriptInvalidHereafter{slot: slot} + end +end From 9ea3a1fcf8837484cedae77d243472f1cbd5c2c8 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:32:37 +0545 Subject: [PATCH 4/8] Transaction body decoder --- lib/sutra/cardano/transaction/tx_body.ex | 139 +++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 lib/sutra/cardano/transaction/tx_body.ex diff --git a/lib/sutra/cardano/transaction/tx_body.ex b/lib/sutra/cardano/transaction/tx_body.ex new file mode 100644 index 0000000..d0c3c5a --- /dev/null +++ b/lib/sutra/cardano/transaction/tx_body.ex @@ -0,0 +1,139 @@ +defmodule Sutra.Cardano.Transaction.TxBody do + @moduledoc """ + Cardano Transaction Body + """ + alias Sutra.Cardano.Address + alias Sutra.Cardano.Transaction.Datum + alias Sutra.Cardano.Transaction.Output + alias Sutra.Utils + alias Sutra.Cardano.Transaction.Certificate + alias Sutra.Cardano.Asset + alias Sutra.Cardano.Transaction.Output.OutputReference + + import Sutra.Data.Cbor, only: [extract_value!: 1] + import Utils, only: [maybe: 3] + use TypedStruct + + typedstruct do + # --- 0 + field(:inputs, [OutputReference.t()]) + # --- 1 + field(:outputs, [Output.t()]) + # --- 2 + field(:fee, :integer) + # --- (3) Slot Number + field(:ttl, :integer) + # --- (4) Certificates -- TODO create Type + field(:certificates, []) + # --- (5) Withdrawals + field(:withdrawals, []) + # --- (6) Update + field(:update, nil) + # --- (7) Auxiliary Data Hash + field(:auxiliary_data_hash, nil) + # --- (8) + field(:validaty_interval_start, :integer) + # --- (9) + field(:mint, :map) + # --- (11) + field(:script_data_hash, :string) + # -- (13) + field(:collateral, [OutputReference.t()]) + # -- (14) + field(:required_signers, [String.t()]) + # -- (15) + field(:network_id, :string) + # -- (16) + field(:collateral_return, :integer) + # -- (17) + field(:total_collateral, :integer) + # -- (18) + field(:reference_inputs, [OutputReference.t()]) + + # --- New Fields in Conway Era + # -- (19) + field(:voting_procedures, any()) + # -- (20) + field(:proposal_procedures, any()) + # -- (21) + field(:current_treasury_value, :integer) + # -- (22) + field(:treasury_donation, :integer) + end + + def decode(tx_body) when is_map(tx_body) do + network_id = if tx_body[15] == 1, do: "mainnet", else: "testnet" + + certificates = + tx_body[4] + |> maybe([], &extract_value!/1) + |> Enum.map(&Certificate.decode/1) + + %__MODULE__{ + inputs: parse_inputs(tx_body[0]), + outputs: Enum.map(tx_body[1], &parse_tx_outputs/1), + fee: Asset.lovelace_of(tx_body[2]), + ttl: tx_body[3], + certificates: certificates, + auxiliary_data_hash: extract_value!(tx_body[7]), + validaty_interval_start: tx_body[8], + mint: maybe(tx_body[9], nil, &Asset.from_plutus/1) |> Utils.ok_or(nil), + script_data_hash: extract_value!(tx_body[11]), + collateral: parse_inputs(extract_value!(tx_body[13]) || []), + network_id: network_id, + collateral_return: maybe(tx_body[16], nil, &parse_tx_outputs/1), + total_collateral: maybe(tx_body[17], nil, &parse_value/1), + reference_inputs: parse_inputs(extract_value!(tx_body[18]) || []) + } + end + + defp parse_inputs(%CBOR.Tag{tag: 258, value: inputs}), do: parse_inputs(inputs) + + defp parse_inputs(inputs) when is_list(inputs) do + Enum.map(inputs, fn [tx_id, index] -> + %OutputReference{ + transaction_id: extract_value!(tx_id), + output_index: index + } + end) + end + + # pre babbage Transaction output + defp parse_tx_outputs([%CBOR.Tag{value: raw_addr} | [amt | dtm_hash]]) + when is_binary(raw_addr) do + %Output{ + address: Address.Parser.decode(raw_addr), + value: parse_value(amt), + datum: dtm_hash |> Utils.safe_head() |> parse_datum() + } + end + + defp parse_tx_outputs(%{0 => %CBOR.Tag{tag: :bytes, value: addr_value}} = ops) do + %Output{ + address: Address.Parser.decode(addr_value), + value: parse_value(ops[1]), + datum: parse_datum(ops[2]), + reference_script: ops[3] + } + end + + # datum_hash = $hash32 + defp parse_datum(datum_hash) when is_binary(datum_hash), + do: %Datum{kind: :datum_hash, value: datum_hash} + + # datum_option = [0, $hash32 // 1, data] + defp parse_datum([0, datum_hash]), do: %Datum{kind: :datum_hash, value: datum_hash} + + defp parse_datum([1, %CBOR.Tag{tag: 24, value: %CBOR.Tag{tag: :bytes, value: data}}]), + do: %Datum{kind: :inline_datum, value: data} + + defp parse_datum(_), do: %Datum{kind: :no_datum} + + defp parse_value(lovelace) when is_integer(lovelace), do: Asset.lovelace_of(lovelace) + + defp parse_value([lovelace, other_assets]) do + with {:ok, assets} <- Asset.from_plutus(other_assets) do + Map.put(assets, "lovelace", lovelace) + end + end +end From d8a37a1843c20f9acc1eaf9f1174a7cf1f9e4ce4 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:34:30 +0545 Subject: [PATCH 5/8] decode transaction --- lib/sutra/cardano/transaction.ex | 47 +++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/sutra/cardano/transaction.ex b/lib/sutra/cardano/transaction.ex index 914c8b0..079fc56 100644 --- a/lib/sutra/cardano/transaction.ex +++ b/lib/sutra/cardano/transaction.ex @@ -1,5 +1,50 @@ defmodule Sutra.Cardano.Transaction do - @moduledoc """ + @moduledoc ~S""" Cardano Transaction """ + + alias Sutra.Cardano.Transaction.TxBody + alias Sutra.Cardano.Transaction.Witness + alias Sutra.Cardano.Transaction.TxBody + alias Sutra.Data.Cbor + alias Sutra.Data.Plutus.PList + + use Sutra.Data + + use TypedStruct + + typedstruct do + field(:tx_body, TxBody.t()) + field(:witnesses, [Witness.t()]) + field(:is_valid, boolean()) + field(:metadata, any()) + end + + def from_hex(cbor) when is_binary(cbor) do + case Sutra.Data.decode(cbor) do + {:ok, data} -> from_cbor(data) + {:error, _} -> {:error, :invalid_cbor} + end + end + + # Conway era transaction + def from_cbor(%PList{value: [tx_body, witness, is_valid, metadata]}) + when is_boolean(is_valid) do + witness = + Enum.reduce(Cbor.extract_value!(witness), [], fn w, acc -> + acc ++ Witness.decode(w) + end) + + %__MODULE__{ + tx_body: TxBody.decode(tx_body), + witnesses: witness, + is_valid: is_valid, + metadata: metadata + } + end + + def from_cbor(%PList{value: values}) do + IO.inspect("Other Era TX ...") + IO.inspect(values) + end end From 35060c1f06e6a34be8126d3b9c9ea6a2a2fae039 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Mon, 11 Nov 2024 09:35:20 +0545 Subject: [PATCH 6/8] small changes --- flake.lock | 8 +++--- flake.nix | 8 +++++- lib/sutra/cardano/asset.ex | 9 ++++-- lib/sutra/cardano/common/pool_relay.ex | 35 ++++++++++++++++++++++++ lib/sutra/cardano/transaction/builder.ex | 0 lib/sutra/cardano/transaction/output.ex | 5 ++++ lib/sutra/cardano/utils.ex | 6 ++++ lib/sutra/data/cbor.ex | 7 +++++ lib/sutra/data/plutus.ex | 11 ++++++-- 9 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 lib/sutra/cardano/common/pool_relay.ex create mode 100644 lib/sutra/cardano/transaction/builder.ex diff --git a/flake.lock b/flake.lock index 48594b3..321cd53 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1705916986, - "narHash": "sha256-iBpfltu6QvN4xMpen6jGGEb6jOqmmVQKUrXdOJ32u8w=", + "lastModified": 1726481836, + "narHash": "sha256-MWTBH4dd5zIz2iatDb8IkqSjIeFum9jAqkFxgHLdzO4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d7f206b723e42edb09d9d753020a84b3061a79d8", + "rev": "20f9370d5f588fb8c72e844c54511cab054b5f40", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 699ebf9..d6364c9 100644 --- a/flake.nix +++ b/flake.nix @@ -1,7 +1,7 @@ { description = "Elixir flake"; inputs = { - nixpkgs = { url = "github:NixOS/nixpkgs/nixos-23.11"; }; + nixpkgs = { url = "github:NixOS/nixpkgs/nixpkgs-unstable"; }; flake-utils = { url = "github:numtide/flake-utils"; }; }; @@ -11,6 +11,12 @@ outputs = { self, nixpkgs, flake-utils }: inherit (pkgs.lib) optional optionals; pkgs = import nixpkgs { inherit system; }; + #elixir = pkgs.beam.packages.erlang_27.elixir.override { + # version = "1.17.2"; + # rev = "47abe2d107e654ccede845356773bcf6e11ef7cb"; + # sha256 = "sha256-8rb2f4CvJzio3QgoxvCv1iz8HooXze0tWUJ4Sc13dxg="; + #}; + in with pkgs; { diff --git a/lib/sutra/cardano/asset.ex b/lib/sutra/cardano/asset.ex index c074ec9..04e3897 100644 --- a/lib/sutra/cardano/asset.ex +++ b/lib/sutra/cardano/asset.ex @@ -23,16 +23,16 @@ defmodule Sutra.Cardano.Asset do {:ok, value} -> value end - Map.put(acc, key, to_asset_class(val)) + Map.put(acc, key, to_asset_class(key, val)) end) {:ok, result} end - defp to_asset_class(%{%CBOR.Tag{tag: :bytes, value: ""} => lovelace}), + defp to_asset_class("lovelace", %{%CBOR.Tag{tag: :bytes, value: ""} => lovelace}), do: lovelace - defp to_asset_class(value) when is_map(value) do + defp to_asset_class(_, value) when is_map(value) do Enum.reduce(value, %{}, fn {key, val}, acc -> {:ok, key} = extract_value(key) Map.put(acc, key, val) @@ -63,4 +63,7 @@ defmodule Sutra.Cardano.Asset do Map.put(acc, key, val) end) end + + def lovelace_of(value) when is_integer(value), do: %{"lovelace" => value} + def lovelace_of(_), do: nil end diff --git a/lib/sutra/cardano/common/pool_relay.ex b/lib/sutra/cardano/common/pool_relay.ex new file mode 100644 index 0000000..5449946 --- /dev/null +++ b/lib/sutra/cardano/common/pool_relay.ex @@ -0,0 +1,35 @@ +defmodule Sutra.Cardano.Common.PoolRelay do + @moduledoc """ + Pool Relay Information + """ + + use TypedStruct + + typedstruct(module: SingleHostAddr) do + field(:port, :integer) + field(:ipv4, :string) + field(:ipv6, :string) + end + + typedstruct(module: SingleHostName) do + field(:port, :integer) + field(:dns_name, :string) + end + + typedstruct(module: MultiHostName) do + field(:dns_name, :string) + end + + def decode([0, port, ipv4, ipv6]) do + %SingleHostAddr{port: port, ipv4: ipv4, ipv6: ipv6} + end + + def decode([1, port, dns_name]) do + %SingleHostName{port: port, dns_name: dns_name} + end + + def decode([2, dns_name]) do + %MultiHostName{dns_name: dns_name} + end +end + diff --git a/lib/sutra/cardano/transaction/builder.ex b/lib/sutra/cardano/transaction/builder.ex new file mode 100644 index 0000000..e69de29 diff --git a/lib/sutra/cardano/transaction/output.ex b/lib/sutra/cardano/transaction/output.ex index 8a842f5..6e66e28 100644 --- a/lib/sutra/cardano/transaction/output.ex +++ b/lib/sutra/cardano/transaction/output.ex @@ -9,6 +9,11 @@ defmodule Sutra.Cardano.Transaction.Output do use Sutra.Data + defdata(name: OutputReference) do + data(:transaction_id, :string) + data(:output_index, :integer) + end + defdata do data(:address, Address) data(:value, Asset) diff --git a/lib/sutra/cardano/utils.ex b/lib/sutra/cardano/utils.ex index b87cfba..abe8a65 100644 --- a/lib/sutra/cardano/utils.ex +++ b/lib/sutra/cardano/utils.ex @@ -12,4 +12,10 @@ defmodule Sutra.Utils do def identity(x), do: x def flip(a, b, f), do: f.(b, a) + + def maybe(nil, f1, _), do: f1 + def maybe(data, _, f2), do: f2.(data) + + def ok_or({:ok, result}, _), do: result + def ok_or(_, default), do: default end diff --git a/lib/sutra/data/cbor.ex b/lib/sutra/data/cbor.ex index c05c85a..6e4c1ad 100644 --- a/lib/sutra/data/cbor.ex +++ b/lib/sutra/data/cbor.ex @@ -7,4 +7,11 @@ defmodule Sutra.Data.Cbor do def extract_value(%CBOR.Tag{value: value}), do: {:ok, value} def extract_value(%Sutra.Data.Plutus.PList{value: value}), do: {:ok, value} def extract_value(value), do: {:ok, value} + + def extract_value!(v) do + case extract_value(v) do + {:ok, value} -> value + {:error, _} -> raise "Invalid CBOR value: #{inspect(v)}" + end + end end diff --git a/lib/sutra/data/plutus.ex b/lib/sutra/data/plutus.ex index 58962a7..45dbf18 100644 --- a/lib/sutra/data/plutus.ex +++ b/lib/sutra/data/plutus.ex @@ -46,15 +46,20 @@ defmodule Sutra.Data.Plutus do end end - @spec decode(binary()) :: {:ok, CBOR.Tag.t()} | {:error, any()} - def decode(raw) do + @spec decode(binary() | CBOR.Tag.t() | integer()) :: {:ok, CBOR.Tag.t()} | {:error, any()} + def decode(val) when is_integer(val), do: {:ok, val} + def decode(%CBOR.Tag{} = cbor_tag), do: {:ok, decode_cbor_tag(cbor_tag)} + + def decode(raw) when is_binary(raw) do with {:ok, bytes} <- normalize_bytes(raw), {:ok, cbor_decoded, _} <- CBOR.decode(bytes) do {:ok, decode_cbor_tag(cbor_decoded)} end end - defp normalize_bytes(str) do + def decode(data), do: {:error, {:invalid_data, data}} + + defp normalize_bytes(str) when is_binary(str) do case Base.decode16(str, case: :mixed) do {:ok, bytes} -> {:ok, bytes} _ -> {:ok, str} From f3910c80979dbaf0027506c89e503337cdd35483 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Tue, 12 Nov 2024 18:59:03 +0545 Subject: [PATCH 7/8] transaction decoding test for certificate related Tx --- .../fixture/transaction_certificate_cbor.json | 50 + .../transaction_certificate_fixture.ex | 1070 +++++++++++++++++ .../cardano/transaction_decoder_test.exs | 27 + 3 files changed, 1147 insertions(+) create mode 100644 test/fixture/transaction_certificate_cbor.json create mode 100644 test/fixture/transaction_certificate_fixture.ex create mode 100644 test/sutra/cardano/transaction_decoder_test.exs diff --git a/test/fixture/transaction_certificate_cbor.json b/test/fixture/transaction_certificate_cbor.json new file mode 100644 index 0000000..26d16db --- /dev/null +++ b/test/fixture/transaction_certificate_cbor.json @@ -0,0 +1,50 @@ +{ + "302dd221": { + "tx_id": "302da83fb39d6e900f31ecc6b53b2e02e87ea990836fd9dcd5186c93ac42d221", + "cbor": "84a500d901028182582055e2606fd2faa05415c721a846767fa1b37fcb477800851f5c2afca23460447000018182583900963dcde8e7ef8cee6beb0115f416da97afccb0c698563e0733a1998fec65e4249708b5dafd1e91d23f2d2d38c460e4d206f78fa18760efc71b00000002361a7772021a0002e2f5031a0479fe6504d90102828a03581c202d6df929b8a626bc39de9e96ef5bfc8122a70265bfc85469ce31da582033c789bd8a61318481c9869ec4d45d2bfb649d0bc8d175f66a6587cf3edc27dc1b000000012a05f2001a0a21fe80d81e820114581de0ec65e4249708b5dafd1e91d23f2d2d38c460e4d206f78fa18760efc7d9010281581cec65e4249708b5dafd1e91d23f2d2d38c460e4d206f78fa18760efc781830119712571382e7463702e65752e6e67726f6b2e696f82783468747470733a2f2f757073747265616d2e6f72672e756b2f6173736574732f70726570726f642f6d657461646174612e6a736f6e58207de1a14fd91a5c307c9816fdbc970bdd724c62c7ea1eb2ba97ac89ee0fb9fb7a83028200581cec65e4249708b5dafd1e91d23f2d2d38c460e4d206f78fa18760efc7581c202d6df929b8a626bc39de9e96ef5bfc8122a70265bfc85469ce31daa100d90102838258203c6446c438cf23330b04e634823aef0272c4d1dc03fe20b6a3f12e52793a923b584097fb7923add275ed49918fbfe1ca0af09c1a24c5e03bef52afe6e913a4c9a8c04ed9d1c86fd76cbf4584e1c8264a078679f3922db473f8f3ab04328b69f9b109825820b449d53faf0cfae07d09c70f039b5210e33f28241ffd7578814fe172d062436f58404da23fa90afa4bc5982d678fb21afa21d2b720c6c16c02a15f6e688f6b4fcd86cd852d520a57a0c6bf20b73a0062a45e9453f6db78c2e56dcd628f144b4a81078258203ad18c8f50db6c2e7c507d56843b3264f13afd2bff320835a37fc3a14d5b862a5840202d3fad06b7e28cbf5f3f9ea715e1573b5dfc40f6eed1e33c82628427b78ac04948557b26e303c6bdbe532b765f1fbe0e110088f2311e2eb37f89fb2c89f708f5f6" + }, + "1e38fd07": { + "tx_id": "1e381d8513d1ca7bd54cc30d61a4ad92e2293cad9818a982454318adbf56fd07", + "cbor": "84a500d90102818258200ac7c67527386e1e4e939497c92d442f6b0d9a46bb18c545f8fd1601aa625a24000181825839000e1eb0eca9e4cc903e52296ae9ca9c27fd1d0519ed12ce4e44533dd31aabc2a4375103d4bc744c34d7139e33298ffdfaa9866badc6f668e11b00000001a0fd3854021a00029f3d031a0475caa404d90102818304581c1c0c7584b3585820786532f62db3c18b324b850e52dfad8ee2fffeea18b1a100d9010282825820b9100ad0ede783b907503df21b8bbcd12705923918be23f978872081deaa76b658406d4ac1d9849f3b9313573848cc5a2202b25bf6ee6f1007f80f8180d8b30a2361a1422cc8a165dae6e49c95e7140f2137d4cf5c64ca0dd1271af1386ca5e9f200825820e821dcd93cbcf42dc1742aaedbe0678ed35f58aa7dcf6cf81d6f51ad0369c6f25840cb7a0c3bb4d5dd13a14cbd05360649b1384c034cecc9d642c8680fe9634371eaea297380cdf8383ba4ffdf647058357bec2f0e0fea426a3bc4d176fd8302b402f5f6" + }, + "b6703275": { + "tx_id": "b67026a02bb1235e466fe56d64c0cd7155abccc2b0f3c646e8cc6bd4a0cf3275", + "cbor": "84a50081825820b929989211af8ca57e2efb4c178ea50978d25b2a15e35ba2ef30d69022c1924e010181825839007eb505be585918dea709480a7b3ff664c72b77f28e8337e7c92d71e16de8be2814a24b0f2bd8918faf3d07685078b94e14303d5333ff4cb11b00000002110f503f021a0002a98d031a04830e87048282008200581c6de8be2814a24b0f2bd8918faf3d07685078b94e14303d5333ff4cb183028200581c6de8be2814a24b0f2bd8918faf3d07685078b94e14303d5333ff4cb1581c9ed23a4a839826d08d7d10f277a91f0e2373ea90251fb33664d52c94a10082825820ff05f056cc742efff9c1e7a8e243bbed8b31b34693dc29be6d65bd84dbb826aa5840164a8e2aa8f364bb17fbc7e4825ff9c9ae351e448bec479820abc085a29dba06d5acf958c8005e3fc19dc7a916256f8809e613798457eef5f3be53194829da048258209d978d3748642e3a3fda302c8a075ba008374e527e37cd029b50e1e131a6cc7658409d4b72d9c6f19696ea73279d7a2e444317b1da3290604a9cf58fd09e5131afc747a920f54d5b25cbec148ae776b23c8306607187eb2034605dd68882f1515605f5f6" + }, + "531f4c12": { + "tx_id": "531f441ddaa4d6753ec1011eff5c0b060b53c2b2c51d4b2cefaad05c0ed04c12", + "cbor": "84a500818258207f946bfb9bbe8135c68d1096b7a52a0f47e715916d501440e7b6dae59d243cb805018182583900ea68ee897733ba2aa41af1a8f1b9b1838d70dfcc61763a74328e6cefbef0e133d1c6f1e1c5401162f355e334909b022480a2c2ebc9225e581b000000033da359c0021a00029e8d031a049b7c39048182018200581cbef0e133d1c6f1e1c5401162f355e334909b022480a2c2ebc9225e58a10082825820953f53addb42a8666afb3ef87d13f600c32b7423bbf221803766758f963e48c45840f9e714489d41b2391aae15c6f8d29b2f3cc61d9e7e1297689eee8175bff671a0abaa7b8c853aa20051bd9c52a6eb2a025b800e670d23f86db0dd3229912b06098258201be03609789c47cf4a3126513d4a412908393ef7dec51ca348dd610058d4f1c658401d1cad1998274a6b9778319d83e2a0c89e74f5eef928768487fbd50fee8615d390c0a605be91df9385ee502fc8161e60b8513a14c97a282295067adb947ed20cf5f6" + }, + "c8776215": { + "tx_id": "c87744872b89df20ef5b2363aaa04eab037c144a64388408b990da06d9d86215", + "cbor": "84a40081825820a4b94f6a211dd03dfe43e66a798ef4268285ec707a65e645c447fd96980e0601000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b00000001a7e72f62ab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18904e4275726e61626c65546f6b656e3219019e5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741865021a000308150481840b8200581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d581c9ed23a4a839826d08d7d10f277a91f0e2373ea90251fb33664d52c941a001e8480a100828258200dd2349193f4d73bff8ed9fea7965e3c44bdc098f1d91d0a2c9af8aa525db71b5840f922f0603d732424d048323443b22ea1705d3e768e430f6393cfdd38424cc33f28d9c8cb9557ce047129c19b01068ff15d11a84f9855d31c98fcb902f2da19088258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f5446758409d8cf0d2ff5cf81778c7a6a1994a79ffeadf8080a9dc3c4d7dfb9ba6ccf98d26bb46959e422b798fa6d70547e6e7b807c85bf1fc7c720aa58526a6e25250b704f5f6" + }, + "6ed6cedc": { + "tx_id": "6ed61d474544baa4c9bbee01a0b706756581319e3569445fec08a3456213cedc", + "cbor": "84a400818258207604e9b3b02f1c67955cacc6049fd70f69547a09ad347c85052aec5d7fd07195000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b00000001a7cf0e2eab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18904e4275726e61626c65546f6b656e3219019e5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741865021a0003086d0481850d8200581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d581c9ed23a4a839826d08d7d10f277a91f0e2373ea90251fb33664d52c9481021a001e8480a100828258200dd2349193f4d73bff8ed9fea7965e3c44bdc098f1d91d0a2c9af8aa525db71b5840696c0e11745821034f23a6e34d7b8f80d6bc3283e2f9ad5cd71db0de93527b40eb1c1212a53bf288fab8c9cfd24911bb80f4b7bedfa4ff0985dff3cbced50b0a8258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f544675840ed6a1c0018f747a0d00a383766d0aa8d0f5668a9841ffa9d6b25f2ffc7682cd0d01a7de0ef85b87929abf501af4313b077a45e75d3af6bc98e9e79989a44f40af5f6" + }, + "16bd4ae9": { + "tx_id": "16bdb2bad71be8b43df33ed41d6c785fbc4722f87600fd10311956898ec94ae9", + "cbor": "84a4008182582037e9aa9b258deb306431e09a862f86cf3d59085ea025bf27a3064e06d0858a77000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b00000001a7f6450fab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18904e4275726e61626c65546f6b656e3219019e5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741865021a000307910481840a8200581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d581c9ed23a4a839826d08d7d10f277a91f0e2373ea90251fb33664d52c948102a100828258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f5446758405e0d1631b7bd4e89cd658779da8eefafb41fbce6747982ee4967acf640f4eb1407ade34156c66577339a6b0acb311b0b721bee35eff2d5d1e205264e6b3414098258200dd2349193f4d73bff8ed9fea7965e3c44bdc098f1d91d0a2c9af8aa525db71b584063c1f5a383c99cee6e9c175febd8764944633ab7c64cde348d7be40d2a85f7473ab24176715cfb2961bbc98c3ce954ffaad86bb86cfa64443798712dab9b2206f5f6" + }, + "a4809f97": { + "tx_id": "a48080fccb70399e145c7aa556b4e8abbed9fa588ec0cde0a29f471317ac9f97", + "cbor": "84a40081825820130663f385984456f5d3f9b1c7eda359f942f325a30218cadeb23413ddaaf6b8000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b00000001a7d51988ab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18904e4275726e61626c65546f6b656e3219019e5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741865021a000303450481840c8200581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d81021a001e8480a100828258200dd2349193f4d73bff8ed9fea7965e3c44bdc098f1d91d0a2c9af8aa525db71b584026446aaeb605a8188637f29e8aeeec1a391570a603e3cfaad3bfef1c12a0cf7d16d7c0e6b3451b0ea53b4a9f920149818cbc1276bfacb8ac0d8d3ff80ee28e0f8258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f544675840f5230da13cd0a6dc14e1c4a43b55a78c14fe4b2edd4fb1179a835f91242a0760ae4eb3e9a780bc7a8600cdb1ec8ca22f5d6da6e69fe3e6742807b06ad76be40bf5f6" + }, + "92714dd1": { + "tx_id": "9271711c197696af2f16070071927e2e20a6354f1240b2aa39ccd2f22d8b4dd1", + "cbor": "84a40081825820fc3cb52653c3f2e0b983ebc10b7634a88816aa1ea01d68aacc40c4b08a669a8401018282583900c7ae56052edfd929202f5146f0fa2d3583a79edb1485f05ff623cbe21c66afb2b2fff29fe041f9a870ea617d926d1f6c558da5941819fbdd1a000f424082583900998d4e8fe3a8b3193ce56407f0803fe0801c7e5765117548a629f6601c66afb2b2fff29fe041f9a870ea617d926d1f6c558da5941819fbdd1a00841a6a021a0002a859048183098200581c1c66afb2b2fff29fe041f9a870ea617d926d1f6c558da5941819fbdd8103a100828258201ddbc3129d9281587dc17694958d0926d8e155f51e4d9f6d3de72a90d318b9ea5840941ba5fa0d71fe52e3661d02683edc36970dfb4a06afe46f64c4ab6f6f1eb1b718f4a897cdd945f010ce1f4a6b4efc2f47c864afcae5938fc497a60a782ae0028258203c791e6f172ac17967ba2125d05e76691684568238d703d0a2b394a7c22f155f5840a32fd3828c56dfe462b94b673f07b3e2cc255c8e1c807e7980ef08ede33fe4e5f7fdd5e3e929f372df6c64ab6edfe6d712e113ad9be028ad31e9c3b07a054d00f5f6" + }, + "089176f3": { + "tx_id": "0891a7e18016b08bfe1bed306c0c12bd68a2e4cc933181659ace22b331e476f3 ", + "cbor": "84a500d90102818258209e8ef69967ae9fb1234d4210453de1c8a5882952ee7fc0b90877af1368239327000181825839005746c1b032f826b5e5256357a713a7ca63988fe2ff862e0396993b97ef0cbd5199d0e460725b3e79d371deb42110d40b778d3bf162777d4c1b0000014cb6cd63de021a0002a045031a0482db0f04d901028184108200581cec47423ff6f9114a36fffcfada2ea1956028ef9ff287ca30f4a860c71a1dcd6500f6a100d9010282825820a4dd1464f31cc3bc36f036ab554d44c0995b6d62764052370190c3a23f331a02584049e521e9ec731b32eff84ff3bc6714a3f27a485ff4eaaef6c28f1a5949cd210e645c4beb385362efa45d7cfe4b8b6174a9d16af24a7d4ee75fb464183db6040d8258209d1597e1f216a140ad40c62a1f67a25b4a9ebef1b136d8fc2073edcaa801d258584048757db45889440f92a9ee5022b959a656783d420719d8f58d65f8065fa96ff95f79e39e24b0deee2ae41664cc1647f0353556f93b85297fd250f4f29c89f60af5f6" + }, + "4ab1f4ed": { + "tx_id": "4ab1cfa507e15828a4eb4ccd004635042c932b29ac97aec72ff409c50fd8f4ed", + "cbor": "84a800818258204ededd73b30fc7c7140bb79ecc072ce800617356809850968e4e5eb2699a465e000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b00000001ab4bc2e6ab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18914e4275726e61626c65546f6b656e321901a15820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741866021a00038470048183118201581c99e21871b90d685cb26c4171169a54e5ed4f26f39dfc161b35fb81121a1dcd65000b582025757b59c698464baccf51976cdc4bcc3e53116cef264082ec8df08e3ed1994a0d818258204ededd73b30fc7c7140bb79ecc072ce800617356809850968e4e5eb2699a465e0010825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b000000018d359716ab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18914e4275726e61626c65546f6b656e321901a15820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741866111a004c4b40a300818258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f54467584061c43126c495e653cf6ccf69ebd24487e4ddc092f7e75ad0dd187671512b0b6b632c531f83679d8ee0d5613d8305ed2fb7843a4e2bd2dc8be0ad5745abb6c3000581840200d87980821920631a0021c9e207815851584f010100323232323225333002323232323253330073370e900418041baa0011324a2601460126ea80045289804980500118040009804001180300098021baa00114984d9595cd2ab9d5573cae855d11f5f6" + }, + "d77f127d": { + "tx_id": "d77f6b57c2fc7b39771ad322808bf5a697ef9edac11d09062e439c6a296e127d", + "cbor": "84a400818258208267a54d323ed85e5271546aa85e888ae4d120d24b49a1a5dec70f3536acfee7000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b000000018d8869dfab581c0d26f1decee50c24498585cb9cba2b6aa629c83023b327bb10fb67b9a14c4d696e745769746864726177182b581c1c05caed08ddd5c9f233f4cb497eeb6e5f685e8e7b842b08897d1dfea14d4d794d696e746564546f6b656e01581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737415581c4613dac79011ebfa5d5837e32b8a8db70b57cbd7ffd89ba108af81aba1474346544f4b454e190114581c501b8b9dce8d7c1247a14bb69d416c621267daa72ebd6c8194293192a14d4d794d696e746564546f6b656e01581c61d96f9000bf5d325da17258ee0693e19d441cecee64825289ee6b7da14c4d696e7457697468647261771821581c665d4dbea856001b880d5749e94384cc486d8c4ee99540d2f65d1570a14d4d794d696e746564546f6b656e01581ccac67dd80f706e084b2aac605288b2ff793475ea43b2313e1ed384aba3534275726e61626c65546f6b656e506c75747573014454657374182a5820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581ceb8b660cf939281c277264389c4086e7c79baf78e08d0c48668420aba14d4d794d696e746564546f6b656e01581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca34d4275726e61626c65546f6b656e18914e4275726e61626c65546f6b656e321901a15820accbfb633f637e3bb1abee40c9539d1effd742cd2716b3b1db9de3aaf3f3779401581cf654f6a31f6c4cc2c39a169f2c022404aa9f19d43137b0448b219a3ea144546573741866021a0003023d048183128200581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420df6a100828258200dd2349193f4d73bff8ed9fea7965e3c44bdc098f1d91d0a2c9af8aa525db71b5840568b50e470f10673d76f72dcad997ec2ac87c57a272edc8fd3b7b0b84dd9ef8cd837a96f614b57386a77c1f9d7a1c5c03c7db259d1c92bd2ee3f24ae488884048258200abb7b89e091dcd3201aea501854a4cb05290862d88b6eb30afa6dfd23f5446758409fc9380a43c1ce583a286ff007206c9e7149d77d7c9c829ae7a0aa23a631d4b5d5566b5c9804091cd8f8293b5494769ad7edf206c3bcf6eda4b410bb77221602f5f6" + } +} diff --git a/test/fixture/transaction_certificate_fixture.ex b/test/fixture/transaction_certificate_fixture.ex new file mode 100644 index 0000000..c5ead99 --- /dev/null +++ b/test/fixture/transaction_certificate_fixture.ex @@ -0,0 +1,1070 @@ +defmodule Sutra.Test.Fixture.TransactionCertificateFixture do + @moduledoc """ + This modules procides helper function and setup transactions for testing + """ + + alias Sutra.Cardano.Transaction + alias Sutra.Cardano.Transaction.Certificate + alias Sutra.Cardano.Transaction.TxBody + alias Sutra.Cardano.Transaction.Witness + + @tx_cbors File.read!("test/fixture/transaction_certificate_cbor.json") |> Jason.decode!() + + def get_certificate_cbors, do: @tx_cbors + + # for TxId: 302da83fb39d6e900f31ecc6b53b2e02e87ea990836fd9dcd5186c93ac42d221 (preprod) + def body_302dd221 do + %TxBody{ + auxiliary_data_hash: nil, + certificates: [ + %Certificate.PoolRegistration{ + cost: %{"lovelace" => 170_000_000}, + margin: 0.05, + metadata: %{ + hash: "7DE1A14FD91A5C307C9816FDBC970BDD724C62C7EA1EB2BA97AC89EE0FB9FB7A", + url: "https://upstream.org.uk/assets/preprod/metadata.json" + }, + owners: ["EC65E4249708B5DAFD1E91D23F2D2D38C460E4D206F78FA18760EFC7"], + pledge: %{"lovelace" => 5_000_000_000}, + pool_key_hash: "202D6DF929B8A626BC39DE9E96EF5BFC8122A70265BFC85469CE31DA", + relays: [ + %Sutra.Cardano.Common.PoolRelay.SingleHostName{ + dns_name: "8.tcp.eu.ngrok.io", + port: 28_965 + } + ], + reward_account: "E0EC65E4249708B5DAFD1E91D23F2D2D38C460E4D206F78FA18760EFC7", + vrf_key_hash: "33C789BD8A61318481C9869EC4D45D2BFB649D0BC8D175F66A6587CF3EDC27DC" + }, + %Certificate.StakeDelegation{ + pool_keyhash: "202D6DF929B8A626BC39DE9E96EF5BFC8122A70265BFC85469CE31DA", + stake_credential: %Sutra.Cardano.Address.Credential{ + credential_type: :vkey, + hash: "EC65E4249708B5DAFD1E91D23F2D2D38C460E4D206F78FA18760EFC7" + } + } + ], + collateral: [], + fee: %{"lovelace" => 189_173}, + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "55E2606FD2FAA05415C721A846767FA1B37FCB477800851F5C2AFCA234604470" + } + ], + mint: nil, + network_id: "testnet", + outputs: [ + %Transaction.Output{ + address: %Sutra.Cardano.Address{ + address_type: :shelley, + network: :testnet, + payment_credential: %Sutra.Cardano.Address.Credential{ + credential_type: :vkey, + hash: "963dcde8e7ef8cee6beb0115f416da97afccb0c698563e0733a1998f" + }, + stake_credential: %Sutra.Cardano.Address.Credential{ + credential_type: :vkey, + hash: "ec65e4249708b5dafd1e91d23f2d2d38c460e4d206f78fa18760efc7" + } + }, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + reference_script: nil, + value: %{"lovelace" => 9_497_638_770} + } + ], + reference_inputs: [], + ttl: 75_103_845 + } + end + + def witness_302dd221 do + [ + %Witness.VkeyWitness{ + signature: + "97FB7923ADD275ED49918FBFE1CA0AF09C1A24C5E03BEF52AFE6E913A4C9A8C04ED9D1C86FD76CBF4584E1C8264A078679F3922DB473F8F3AB04328B69F9B109", + vkey: "3C6446C438CF23330B04E634823AEF0272C4D1DC03FE20B6A3F12E52793A923B" + }, + %Witness.VkeyWitness{ + signature: + "4DA23FA90AFA4BC5982D678FB21AFA21D2B720C6C16C02A15F6E688F6B4FCD86CD852D520A57A0C6BF20B73A0062A45E9453F6DB78C2E56DCD628F144B4A8107", + vkey: "B449D53FAF0CFAE07D09C70F039B5210E33F28241FFD7578814FE172D062436F" + }, + %Witness.VkeyWitness{ + signature: + "202D3FAD06B7E28CBF5F3F9EA715E1573B5DFC40F6EED1E33C82628427B78AC04948557B26E303C6BDBE532B765F1FBE0E110088F2311E2EB37F89FB2C89F708", + vkey: "3AD18C8F50DB6C2E7C507D56843B3264F13AFD2BFF320835A37FC3A14D5B862A" + } + ] + end + + # For TxId: 1e381d8513d1ca7bd54cc30d61a4ad92e2293cad9818a982454318adbf56fd07 (preprod) + + def body_1e38fd07 do + %TxBody{ + auxiliary_data_hash: nil, + certificates: [ + %Certificate.PoolRetirement{ + epoch_no: 177, + pool_keyhash: + <<28, 12, 117, 132, 179, 88, 88, 32, 120, 101, 50, 246, 45, 179, 193, 139, 50, 75, + 133, 14, 82, 223, 173, 142, 226, 255, 254, 234>> + } + ], + collateral: [], + collateral_return: nil, + current_treasury_value: nil, + fee: %{"lovelace" => 171_837}, + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "0AC7C67527386E1E4E939497C92D442F6B0D9A46BB18C545F8FD1601AA625A24" + } + ], + mint: nil, + network_id: "testnet", + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 6_995_916_884}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "1aabc2a4375103d4bc744c34d7139e33298ffdfaa9866badc6f668e1", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "0e1eb0eca9e4cc903e52296ae9ca9c27fd1d0519ed12ce4e44533dd3", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + reference_inputs: [], + ttl: 74_828_452 + } + end + + def witness_1e38fd07 do + [ + %Witness.VkeyWitness{ + signature: + "6D4AC1D9849F3B9313573848CC5A2202B25BF6EE6F1007F80F8180D8B30A2361A1422CC8A165DAE6E49C95E7140F2137D4CF5C64CA0DD1271AF1386CA5E9F200", + vkey: "B9100AD0EDE783B907503DF21B8BBCD12705923918BE23F978872081DEAA76B6" + }, + %Witness.VkeyWitness{ + signature: + "CB7A0C3BB4D5DD13A14CBD05360649B1384C034CECC9D642C8680FE9634371EAEA297380CDF8383BA4FFDF647058357BEC2F0E0FEA426A3BC4D176FD8302B402", + vkey: "E821DCD93CBCF42DC1742AAEDBE0678ED35F58AA7DCF6CF81D6F51AD0369C6F2" + } + ] + end + + # For TxId: b67026a02bb1235e466fe56d64c0cd7155abccc2b0f3c646e8cc6bd4a0cf3275 (preprod) + def body_b6703275 do + %Transaction.TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.StakeRegistration{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "6DE8BE2814A24B0F2BD8918FAF3D07685078B94E14303D5333FF4CB1", + credential_type: :vkey + } + }, + %Certificate.StakeDelegation{ + pool_keyhash: "9ED23A4A839826D08D7D10F277A91F0E2373EA90251FB33664D52C94", + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "6DE8BE2814A24B0F2BD8918FAF3D07685078B94E14303D5333FF4CB1", + credential_type: :vkey + } + } + ], + ttl: 75_697_799, + fee: %{"lovelace" => 174_477}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 8_876_150_847}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "6de8be2814a24b0f2bd8918faf3d07685078b94e14303d5333ff4cb1", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "7eb505be585918dea709480a7b3ff664c72b77f28e8337e7c92d71e1", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 1, + transaction_id: "B929989211AF8CA57E2EFB4C178EA50978D25B2A15E35BA2EF30D69022C1924E" + } + ] + } + end + + def witness_b6703275 do + [ + %Witness.VkeyWitness{ + signature: + "164A8E2AA8F364BB17FBC7E4825FF9C9AE351E448BEC479820ABC085A29DBA06D5ACF958C8005E3FC19DC7A916256F8809E613798457EEF5F3BE53194829DA04", + vkey: "FF05F056CC742EFFF9C1E7A8E243BBED8B31B34693DC29BE6D65BD84DBB826AA" + }, + %Witness.VkeyWitness{ + signature: + "9D4B72D9C6F19696EA73279D7A2E444317B1DA3290604A9CF58FD09E5131AFC747A920F54D5B25CBEC148AE776B23C8306607187EB2034605DD68882F1515605", + vkey: "9D978D3748642E3A3FDA302C8A075BA008374E527E37CD029B50E1E131A6CC76" + } + ] + end + + # for TxId: 531f441ddaa4d6753ec1011eff5c0b060b53c2b2c51d4b2cefaad05c0ed04c12 (preprod) + def body_531f4c12 do + %TxBody{ + certificates: [ + %Certificate.StakeDeRegistration{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "BEF0E133D1C6F1E1C5401162F355E334909B022480A2C2EBC9225E58", + credential_type: :vkey + } + } + ], + collateral: [], + fee: %{"lovelace" => 171_661}, + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 5, + transaction_id: "7F946BFB9BBE8135C68D1096B7A52A0F47E715916D501440E7B6DAE59D243CB8" + } + ], + network_id: "testnet", + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 13_919_017_408}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "bef0e133d1c6f1e1c5401162f355e334909b022480a2c2ebc9225e58", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "ea68ee897733ba2aa41af1a8f1b9b1838d70dfcc61763a74328e6cef", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + reference_inputs: [], + ttl: 77_298_745 + } + end + + def witness_531f4c12 do + [ + %Witness.VkeyWitness{ + signature: + "F9E714489D41B2391AAE15C6F8D29B2F3CC61D9E7E1297689EEE8175BFF671A0ABAA7B8C853AA20051BD9C52A6EB2A025B800E670D23F86DB0DD3229912B0609", + vkey: "953F53ADDB42A8666AFB3EF87D13F600C32B7423BBF221803766758F963E48C4" + }, + %Witness.VkeyWitness{ + signature: + "1D1CAD1998274A6B9778319D83E2A0C89E74F5EEF928768487FBD50FEE8615D390C0A605BE91DF9385EE502FC8161E60B8513A14C97A282295067ADB947ED20C", + vkey: "1BE03609789C47CF4A3126513D4A412908393EF7DEC51CA348DD610058D4F1C6" + } + ] + end + + # for txId: c87744872b89df20ef5b2363aaa04eab037c144a64388408b990da06d9d86215 (preprod) + + def body_c8776215 do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.StakeRegDelegCert{ + deposit: %{"lovelace" => 2_000_000}, + pool_keyhash: "9ED23A4A839826D08D7D10F277A91F0E2373EA90251FB33664D52C94", + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064B671634D14CB8D543E71DD8EB437A47EFB47B0B22882866C420D", + credential_type: :vkey + } + } + ], + fee: %{"lovelace" => 198_677}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 144, + "4275726E61626C65546F6B656E32" => 414, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 101}, + "lovelace" => 7_111_913_314 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "A4B94F6A211DD03DFE43E66A798EF4268285EC707A65E645C447FD96980E0601" + } + ] + } + end + + def witness_c8776215 do + [ + %Witness.VkeyWitness{ + signature: + "F922F0603D732424D048323443B22EA1705D3E768E430F6393CFDD38424CC33F28D9C8CB9557CE047129C19B01068FF15D11A84F9855D31C98FCB902F2DA1908", + vkey: "0DD2349193F4D73BFF8ED9FEA7965E3C44BDC098F1D91D0A2C9AF8AA525DB71B" + }, + %Witness.VkeyWitness{ + signature: + "9D8CF0D2FF5CF81778C7A6A1994A79FFEADF8080A9DC3C4D7DFB9BA6CCF98D26BB46959E422B798FA6D70547E6E7B807C85BF1FC7C720AA58526A6E25250B704", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + } + ] + end + + # for TxId: 6ed61d474544baa4c9bbee01a0b706756581319e3569445fec08a3456213cedc (Preprod) + + def body_6ed6cedc do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.StakeVoteRegDelegCert{ + deposit: %{"lovelace" => 2_000_000}, + drep: %Certificate.Drep{drep_value: nil, drep_type: 2}, + pool_keyhash: "9ED23A4A839826D08D7D10F277A91F0E2373EA90251FB33664D52C94", + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064B671634D14CB8D543E71DD8EB437A47EFB47B0B22882866C420D", + credential_type: :vkey + } + } + ], + fee: %{"lovelace" => 198_765}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 144, + "4275726E61626C65546F6B656E32" => 414, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 101}, + "lovelace" => 7_110_331_950 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "7604E9B3B02F1C67955CACC6049FD70F69547A09AD347C85052AEC5D7FD07195" + } + ] + } + end + + def witness_6ed6cedc do + [ + %Witness.VkeyWitness{ + signature: + "696C0E11745821034F23A6E34D7B8F80D6BC3283E2F9AD5CD71DB0DE93527B40EB1C1212A53BF288FAB8C9CFD24911BB80F4B7BEDFA4FF0985DFF3CBCED50B0A", + vkey: "0DD2349193F4D73BFF8ED9FEA7965E3C44BDC098F1D91D0A2C9AF8AA525DB71B" + }, + %Witness.VkeyWitness{ + signature: + "ED6A1C0018F747A0D00A383766D0AA8D0F5668A9841FFA9D6B25F2FFC7682CD0D01A7DE0EF85B87929ABF501AF4313B077A45E75D3AF6BC98E9E79989A44F40A", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + } + ] + end + + # for TxId: 16bdb2bad71be8b43df33ed41d6c785fbc4722f87600fd10311956898ec94ae9 (Preprod) + def body_16bd4ae9 do + %Transaction.TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.StakeVoteDelegCert{ + drep: %Certificate.Drep{drep_value: nil, drep_type: 2}, + pool_keyhash: "9ED23A4A839826D08D7D10F277A91F0E2373EA90251FB33664D52C94", + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064B671634D14CB8D543E71DD8EB437A47EFB47B0B22882866C420D", + credential_type: :vkey + } + } + ], + fee: %{"lovelace" => 198_545}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 144, + "4275726E61626C65546F6B656E32" => 414, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 101}, + "lovelace" => 7_112_901_903 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "37E9AA9B258DEB306431E09A862F86CF3D59085EA025BF27A3064E06D0858A77" + } + ] + } + end + + def witness_16bd4ae9 do + [ + %Witness.VkeyWitness{ + signature: + "5E0D1631B7BD4E89CD658779DA8EEFAFB41FBCE6747982EE4967ACF640F4EB1407ADE34156C66577339A6B0ACB311B0B721BEE35EFF2D5D1E205264E6B341409", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + }, + %Witness.VkeyWitness{ + signature: + "63C1F5A383C99CEE6E9C175FEBD8764944633AB7C64CDE348D7BE40D2A85F7473AB24176715CFB2961BBC98C3CE954FFAAD86BB86CFA64443798712DAB9B2206", + vkey: "0DD2349193F4D73BFF8ED9FEA7965E3C44BDC098F1D91D0A2C9AF8AA525DB71B" + } + ] + end + + # For TxId: a48080fccb70399e145c7aa556b4e8abbed9fa588ec0cde0a29f471317ac9f97 (Preprod) + + def body_a4809f97 do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.VoteRegDelegCert{ + deposit: %{"lovelace" => 2_000_000}, + drep: %Certificate.Drep{drep_value: nil, drep_type: 2}, + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064B671634D14CB8D543E71DD8EB437A47EFB47B0B22882866C420D", + credential_type: :vkey + } + } + ], + fee: %{"lovelace" => 197_445}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 144, + "4275726E61626C65546F6B656E32" => 414, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 101}, + "lovelace" => 7_110_728_072 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "130663F385984456F5D3F9B1C7EDA359F942F325A30218CADEB23413DDAAF6B8" + } + ] + } + end + + def witness_a4809f97 do + [ + %Witness.VkeyWitness{ + signature: + "26446AAEB605A8188637F29E8AEEEC1A391570A603E3CFAAD3BFEF1C12A0CF7D16D7C0E6B3451B0EA53B4A9F920149818CBC1276BFACB8AC0D8D3FF80EE28E0F", + vkey: "0DD2349193F4D73BFF8ED9FEA7965E3C44BDC098F1D91D0A2C9AF8AA525DB71B" + }, + %Witness.VkeyWitness{ + signature: + "F5230DA13CD0A6DC14E1C4A43B55A78C14FE4B2EDD4FB1179A835F91242A0760AE4EB3E9A780BC7A8600CDB1EC8CA22F5D6DA6E69FE3E6742807B06AD76BE40B", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + } + ] + end + + # For TxId: 9271711c197696af2f16070071927e2e20a6354f1240b2aa39ccd2f22d8b4dd1 (Preprod) + + def body_92714dd1 do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.VoteDelegCert{ + drep: %Certificate.Drep{drep_value: nil, drep_type: 3}, + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "1C66AFB2B2FFF29FE041F9A870EA617D926D1F6C558DA5941819FBDD", + credential_type: :vkey + } + } + ], + ttl: nil, + fee: %{"lovelace" => 174_169}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 1_000_000}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "1c66afb2b2fff29fe041f9a870ea617d926d1f6c558da5941819fbdd", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "c7ae56052edfd929202f5146f0fa2d3583a79edb1485f05ff623cbe2", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + }, + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 8_657_514}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "1c66afb2b2fff29fe041f9a870ea617d926d1f6c558da5941819fbdd", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "998d4e8fe3a8b3193ce56407f0803fe0801c7e5765117548a629f660", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 1, + transaction_id: "FC3CB52653C3F2E0B983EBC10B7634A88816AA1EA01D68AACC40C4B08A669A84" + } + ] + } + end + + def witness_92714dd1 do + [ + %Witness.VkeyWitness{ + signature: + "941BA5FA0D71FE52E3661D02683EDC36970DFB4A06AFE46F64C4AB6F6F1EB1B718F4A897CDD945F010CE1F4A6B4EFC2F47C864AFCAE5938FC497A60A782AE002", + vkey: "1DDBC3129D9281587DC17694958D0926D8E155F51E4D9F6D3DE72A90D318B9EA" + }, + %Witness.VkeyWitness{ + signature: + "A32FD3828C56DFE462B94B673F07B3E2CC255C8E1C807E7980EF08EDE33FE4E5F7FDD5E3E929F372DF6C64AB6EDFE6D712E113AD9BE028AD31E9C3B07A054D00", + vkey: "3C791E6F172AC17967BA2125D05E76691684568238D703D0A2B394A7C22F155F" + } + ] + end + + # For TxId: 0891a7e18016b08bfe1bed306c0c12bd68a2e4cc933181659ace22b331e476f3 (Preprod) + def body_089176f3 do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.RegDrepCert{ + anchor: nil, + deposit: %{"lovelace" => 500_000_000}, + drep_credential: %Sutra.Cardano.Address.Credential{ + hash: "EC47423FF6F9114A36FFFCFADA2EA1956028EF9FF287CA30F4A860C7", + credential_type: :vkey + } + } + ], + ttl: 75_684_623, + fee: %{"lovelace" => 172_101}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{"lovelace" => 1_428_996_056_030}, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "ef0cbd5199d0e460725b3e79d371deb42110d40b778d3bf162777d4c", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "5746c1b032f826b5e5256357a713a7ca63988fe2ff862e0396993b97", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "9E8EF69967AE9FB1234D4210453DE1C8A5882952EE7FC0B90877AF1368239327" + } + ] + } + end + + def witness_089176f3 do + [ + %Witness.VkeyWitness{ + signature: + "49E521E9EC731B32EFF84FF3BC6714A3F27A485FF4EAAEF6C28F1A5949CD210E645C4BEB385362EFA45D7CFE4B8B6174A9D16AF24A7D4EE75FB464183DB6040D", + vkey: "A4DD1464F31CC3BC36F036AB554D44C0995B6D62764052370190C3A23F331A02" + }, + %Witness.VkeyWitness{ + signature: + "48757DB45889440F92A9EE5022B959A656783D420719D8F58D65F8065FA96FF95F79E39E24B0DEEE2AE41664CC1647F0353556F93B85297FD250F4F29C89F60A", + vkey: "9D1597E1F216A140AD40C62A1F67A25B4A9EBEF1B136D8FC2073EDCAA801D258" + } + ] + end + + # For TxId: 4ab1cfa507e15828a4eb4ccd004635042c932b29ac97aec72ff409c50fd8f4ed (preprod) + + def body_4ab1f4ed do + %Transaction.TxBody{ + reference_inputs: [], + total_collateral: %{"lovelace" => 5_000_000}, + collateral_return: %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 145, + "4275726E61626C65546F6B656E32" => 417, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 102}, + "lovelace" => 6_664_066_838 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + }, + network_id: "testnet", + collateral: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "4EDEDD73B30FC7C7140BB79ECC072CE800617356809850968E4E5EB2699A465E" + } + ], + script_data_hash: "25757B59C698464BACCF51976CDC4BCC3E53116CEF264082EC8DF08E3ED1994A", + certificates: [ + %Certificate.UnRegDrepCert{ + deposit: %{"lovelace" => 500_000_000}, + drep_credential: %Sutra.Cardano.Address.Credential{ + hash: "99E21871B90D685CB26C4171169A54E5ED4F26F39DFC161B35FB8112", + credential_type: :script + } + } + ], + ttl: nil, + fee: %{"lovelace" => 230_512}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 145, + "4275726E61626C65546F6B656E32" => 417, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 102}, + "lovelace" => 7_168_836_326 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "4EDEDD73B30FC7C7140BB79ECC072CE800617356809850968E4E5EB2699A465E" + } + ] + } + end + + def witness_4ab1f4ed do + [ + %Witness.VkeyWitness{ + signature: + "61C43126C495E653CF6CCF69EBD24487E4DDC092F7E75AD0DD187671512B0B6B632C531F83679D8EE0D5613D8305ED2FB7843A4E2BD2DC8BE0AD5745ABB6C300", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + }, + %Witness.Redeemer{ + is_legacy: true, + exunits: {8291, 2_214_370}, + data: %Sutra.Data.Plutus.Constr{fields: [], index: 0}, + index: 0, + tag: :cert + }, + %Witness.ScriptWitness{ + data: [ + "584F010100323232323225333002323232323253330073370E900418041BAA0011324A2601460126EA80045289804980500118040009804001180300098021BAA00114984D9595CD2AB9D5573CAE855D11" + ], + script_type: :plutus_v3 + } + ] + end + + # For TxId: d77f6b57c2fc7b39771ad322808bf5a697ef9edac11d09062e439c6a296e127d (Preprod) + + def body_d77f127d do + %TxBody{ + reference_inputs: [], + network_id: "testnet", + collateral: [], + certificates: [ + %Certificate.UpdateDrepCert{ + anchor: nil, + drep_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064B671634D14CB8D543E71DD8EB437A47EFB47B0B22882866C420D", + credential_type: :vkey + } + } + ], + fee: %{"lovelace" => 197_181}, + outputs: [ + %Transaction.Output{ + reference_script: nil, + datum: %Transaction.Datum{kind: :no_datum, value: nil}, + value: %{ + "0D26F1DECEE50C24498585CB9CBA2B6AA629C83023B327BB10FB67B9" => %{ + "4D696E745769746864726177" => 43 + }, + "1C05CAED08DDD5C9F233F4CB497EEB6E5F685E8E7B842B08897D1DFE" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "22691D3D969ECF5802226290C2FB98E2BC08522D5B726C1F5F400105" => %{"54657374" => 21}, + "4613DAC79011EBFA5D5837E32B8A8DB70B57CBD7FFD89BA108AF81AB" => %{ + "4346544F4B454E" => 276 + }, + "501B8B9DCE8D7C1247A14BB69D416C621267DAA72EBD6C8194293192" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "61D96F9000BF5D325DA17258EE0693E19D441CECEE64825289EE6B7D" => %{ + "4D696E745769746864726177" => 33 + }, + "665D4DBEA856001B880D5749E94384CC486D8C4EE99540D2F65D1570" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "CAC67DD80F706E084B2AAC605288B2FF793475EA43B2313E1ED384AB" => %{ + "4275726E61626C65546F6B656E506C75747573" => 1, + "54657374" => 42, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "EB8B660CF939281C277264389C4086E7C79BAF78E08D0C48668420AB" => %{ + "4D794D696E746564546F6B656E" => 1 + }, + "EF6ED47A6917A3CBBEB46561E8853DA969343794D66128598A34AF2C" => %{ + "4275726E61626C65546F6B656E" => 145, + "4275726E61626C65546F6B656E32" => 417, + "ACCBFB633F637E3BB1ABEE40C9539D1EFFD742CD2716B3B1DB9DE3AAF3F37794" => 1 + }, + "F654F6A31F6C4CC2C39A169F2C022404AA9F19D43137B0448B219A3E" => %{"54657374" => 102}, + "lovelace" => 6_669_494_751 + }, + address: %Sutra.Cardano.Address{ + stake_credential: %Sutra.Cardano.Address.Credential{ + hash: "5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d", + credential_type: :vkey + }, + payment_credential: %Sutra.Cardano.Address.Credential{ + hash: "9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50", + credential_type: :vkey + }, + address_type: :shelley, + network: :testnet + } + } + ], + inputs: [ + %Transaction.Output.OutputReference{ + output_index: 0, + transaction_id: "8267A54D323ED85E5271546AA85E888AE4D120D24B49A1A5DEC70F3536ACFEE7" + } + ] + } + end + + def witness_d77f127d do + [ + %Witness.VkeyWitness{ + signature: + "568B50E470F10673D76F72DCAD997EC2AC87C57A272EDC8FD3B7B0B84DD9EF8CD837A96F614B57386A77C1F9D7A1C5C03C7DB259D1C92BD2EE3F24AE48888404", + vkey: "0DD2349193F4D73BFF8ED9FEA7965E3C44BDC098F1D91D0A2C9AF8AA525DB71B" + }, + %Witness.VkeyWitness{ + signature: + "9FC9380A43C1CE583A286FF007206C9E7149D77D7C9C829AE7A0AA23A631D4B5D5566B5C9804091CD8F8293B5494769AD7EDF206C3BCF6EDA4B410BB77221602", + vkey: "0ABB7B89E091DCD3201AEA501854A4CB05290862D88B6EB30AFA6DFD23F54467" + } + ] + end +end diff --git a/test/sutra/cardano/transaction_decoder_test.exs b/test/sutra/cardano/transaction_decoder_test.exs new file mode 100644 index 0000000..fbeb085 --- /dev/null +++ b/test/sutra/cardano/transaction_decoder_test.exs @@ -0,0 +1,27 @@ +defmodule Sutra.Cardano.TransactionDecoderTest do + @moduledoc false + + use ExUnit.Case + + alias Sutra.Cardano.Transaction + alias Sutra.Test.Fixture.TransactionCertificateFixture + + @cert_cbor_info TransactionCertificateFixture.get_certificate_cbors() + + describe "Certificate Related transaction" do + test "certificate from multiple certificate related transaction" do + Enum.map(Map.keys(@cert_cbor_info), fn k -> + assert %Transaction{} = tx = Transaction.from_hex(@cert_cbor_info[k]["cbor"]) + + assert tx.tx_body == + apply(TransactionCertificateFixture, String.to_atom("body_" <> k), []) + + assert tx.witnesses == + apply(TransactionCertificateFixture, String.to_atom("witness_" <> k), []) + + assert tx.metadata == nil + assert tx.is_valid + end) + end + end +end From 527656ad8d8874aa1aa413e38bef98733ef54224 Mon Sep 17 00:00:00 2001 From: piyushthapa Date: Tue, 12 Nov 2024 19:00:01 +0545 Subject: [PATCH 8/8] make credo happy --- lib/sutra/cardano/common/pool_relay.ex | 1 - lib/sutra/cardano/transaction.ex | 8 +++---- lib/sutra/cardano/transaction/certificate.ex | 21 +++++++++++-------- lib/sutra/cardano/transaction/tx_body.ex | 6 +++--- lib/sutra/cardano/transaction/witness.ex | 2 +- lib/sutra/data/cbor.ex | 2 +- mix.exs | 4 ++++ test/sutra/cardano/asset_test.exs | 4 ++-- test/sutra/cardano/transaction/datum_test.exs | 4 ++-- .../sutra/cardano/transaction/output_test.exs | 8 +++---- 10 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/sutra/cardano/common/pool_relay.ex b/lib/sutra/cardano/common/pool_relay.ex index 5449946..abe2613 100644 --- a/lib/sutra/cardano/common/pool_relay.ex +++ b/lib/sutra/cardano/common/pool_relay.ex @@ -32,4 +32,3 @@ defmodule Sutra.Cardano.Common.PoolRelay do %MultiHostName{dns_name: dns_name} end end - diff --git a/lib/sutra/cardano/transaction.ex b/lib/sutra/cardano/transaction.ex index 079fc56..13d5595 100644 --- a/lib/sutra/cardano/transaction.ex +++ b/lib/sutra/cardano/transaction.ex @@ -5,7 +5,6 @@ defmodule Sutra.Cardano.Transaction do alias Sutra.Cardano.Transaction.TxBody alias Sutra.Cardano.Transaction.Witness - alias Sutra.Cardano.Transaction.TxBody alias Sutra.Data.Cbor alias Sutra.Data.Plutus.PList @@ -43,8 +42,9 @@ defmodule Sutra.Cardano.Transaction do } end - def from_cbor(%PList{value: values}) do - IO.inspect("Other Era TX ...") - IO.inspect(values) + def from_cbor(%PList{value: _values}) do + raise """ + Only Conway era transaction supported + """ end end diff --git a/lib/sutra/cardano/transaction/certificate.ex b/lib/sutra/cardano/transaction/certificate.ex index c434f77..df3abca 100644 --- a/lib/sutra/cardano/transaction/certificate.ex +++ b/lib/sutra/cardano/transaction/certificate.ex @@ -3,14 +3,14 @@ defmodule Sutra.Cardano.Transaction.Certificate do Cardano Transaction Certificate """ + alias Sutra.Cardano.Address + alias Sutra.Cardano.Address.Credential alias Sutra.Cardano.Asset + alias Sutra.Cardano.Common.PoolRelay + alias Sutra.Cardano.Transaction.Certificate.Drep alias Sutra.Cardano.Transaction.Certificate.PoolRegistration alias Sutra.Cardano.Transaction.Certificate.PoolRetirement - alias Sutra.Cardano.Transaction.Certificate.Drep - alias Sutra.Cardano.Address - alias Sutra.Cardano.Common.PoolRelay alias Sutra.Cardano.Transaction.Certificate.StakeRegistration - alias Sutra.Cardano.Address.Credential import Sutra.Data.Cbor, only: [extract_value!: 1] import Sutra.Utils, only: [maybe: 3] @@ -174,9 +174,12 @@ defmodule Sutra.Cardano.Transaction.Certificate do cost: Asset.lovelace_of(cost), margin: n / d, reward_account: extract_value!(reward_accont), - owners: Enum.map(owners, &extract_value!/1), - relays: Enum.map(relays, &PoolRelay.decode/1), - metadata: maybe(pool_metadata, nil, fn [u, h] -> %{url: u, hash: h} end) + owners: Enum.map(extract_value!(owners), &extract_value!/1), + relays: Enum.map(extract_value!(relays), &PoolRelay.decode/1), + metadata: + maybe(pool_metadata, nil, fn [u, h] -> + %{url: extract_value!(u), hash: extract_value!(h)} + end) } end @@ -269,9 +272,9 @@ defmodule Sutra.Cardano.Transaction.Certificate do } end - defp parse_credential([cred_type, %CBOR.Tag{value: stake_credential}]) do + defp parse_credential([cred_type, %CBOR.Tag{} = stake_credential]) do credential_type = if cred_type == 0, do: :vkey, else: :script - %Credential{credential_type: credential_type, hash: stake_credential} + %Credential{credential_type: credential_type, hash: extract_value!(stake_credential)} end def decode_drep([0, v]), do: %Drep{drep_type: :vkey, drep_value: extract_value!(v)} diff --git a/lib/sutra/cardano/transaction/tx_body.ex b/lib/sutra/cardano/transaction/tx_body.ex index d0c3c5a..fbf823f 100644 --- a/lib/sutra/cardano/transaction/tx_body.ex +++ b/lib/sutra/cardano/transaction/tx_body.ex @@ -3,12 +3,12 @@ defmodule Sutra.Cardano.Transaction.TxBody do Cardano Transaction Body """ alias Sutra.Cardano.Address + alias Sutra.Cardano.Asset + alias Sutra.Cardano.Transaction.Certificate alias Sutra.Cardano.Transaction.Datum alias Sutra.Cardano.Transaction.Output - alias Sutra.Utils - alias Sutra.Cardano.Transaction.Certificate - alias Sutra.Cardano.Asset alias Sutra.Cardano.Transaction.Output.OutputReference + alias Sutra.Utils import Sutra.Data.Cbor, only: [extract_value!: 1] import Utils, only: [maybe: 3] diff --git a/lib/sutra/cardano/transaction/witness.ex b/lib/sutra/cardano/transaction/witness.ex index ff92d91..6e2fbf5 100644 --- a/lib/sutra/cardano/transaction/witness.ex +++ b/lib/sutra/cardano/transaction/witness.ex @@ -23,7 +23,7 @@ defmodule Sutra.Cardano.Transaction.Witness do field(:tag, redeemer_tag()) field(:index, integer()) - field(:data, Sutra.Data.Plutus.t()) + field(:data, Plutus.t()) field(:exunits, {integer(), integer()}) field(:is_legacy, boolean(), default: false) diff --git a/lib/sutra/data/cbor.ex b/lib/sutra/data/cbor.ex index 6e4c1ad..5b45be3 100644 --- a/lib/sutra/data/cbor.ex +++ b/lib/sutra/data/cbor.ex @@ -3,7 +3,7 @@ defmodule Sutra.Data.Cbor do CBOR handling """ - + def extract_value(%CBOR.Tag{tag: :bytes, value: value}), do: {:ok, Base.encode16(value)} def extract_value(%CBOR.Tag{value: value}), do: {:ok, value} def extract_value(%Sutra.Data.Plutus.PList{value: value}), do: {:ok, value} def extract_value(value), do: {:ok, value} diff --git a/mix.exs b/mix.exs index 673ec29..cb3ed54 100644 --- a/mix.exs +++ b/mix.exs @@ -6,6 +6,7 @@ defmodule Sutra.MixProject do app: :sutra_offchain, version: "0.1.0", elixir: "~> 1.15", + elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps() ] @@ -18,6 +19,9 @@ defmodule Sutra.MixProject do ] end + defp elixirc_paths(:test), do: ["lib", "test/support", "test/fixture"] + defp elixirc_paths(_), do: ["lib"] + # Run "mix help deps" to learn about dependencies. defp deps do [ diff --git a/test/sutra/cardano/asset_test.exs b/test/sutra/cardano/asset_test.exs index da4b422..b51cd01 100644 --- a/test/sutra/cardano/asset_test.exs +++ b/test/sutra/cardano/asset_test.exs @@ -19,8 +19,8 @@ defmodule Sutra.Cardano.AssetTest do assert {:ok, %{ "lovelace" => 1_000_000, - "policy-id-1" => %{"tkn1" => 100, "tkn2" => 200}, - "policy-id-2" => %{"tkn3" => 300} + "706F6C6963792D69642D31" => %{"746B6E31" => 100, "746B6E32" => 200}, + "706F6C6963792D69642D32" => %{"746B6E33" => 300} }} = Asset.from_plutus(@asset_cbor["with_token"]) end diff --git a/test/sutra/cardano/transaction/datum_test.exs b/test/sutra/cardano/transaction/datum_test.exs index 21374f8..6799cc7 100644 --- a/test/sutra/cardano/transaction/datum_test.exs +++ b/test/sutra/cardano/transaction/datum_test.exs @@ -13,10 +13,10 @@ defmodule Sutra.Cardano.Transaction.DatumTest do test "from_plutus/1" do assert {:ok, %Datum{kind: :no_datum, value: nil}} == Datum.from_plutus(@no_datum_cbor) - assert {:ok, %Datum{kind: :inline_datum, value: "\x9F\x01\x02\x03\xFF"}} == + assert {:ok, %Datum{kind: :inline_datum, value: "9F010203FF"}} == Datum.from_plutus(@inline_datum_cbor) - assert {:ok, %Datum{kind: :datum_hash, value: "some-datum-hash"}} == + assert {:ok, %Datum{kind: :datum_hash, value: "736F6D652D646174756D2D68617368"}} == Datum.from_plutus(@datum_hash_cbor) end diff --git a/test/sutra/cardano/transaction/output_test.exs b/test/sutra/cardano/transaction/output_test.exs index 5391579..7f6d681 100644 --- a/test/sutra/cardano/transaction/output_test.exs +++ b/test/sutra/cardano/transaction/output_test.exs @@ -49,7 +49,7 @@ defmodule Sutra.Cardano.Transaction.OutputTest do }, stake_credential: nil }, - datum: %Datum{kind: :datum_hash, value: "some-hash"}, + datum: %Datum{kind: :datum_hash, value: "736F6D652D68617368"}, reference_script: nil, value: %{ "lovelace" => 1_000_000 @@ -67,7 +67,7 @@ defmodule Sutra.Cardano.Transaction.OutputTest do }, stake_credential: nil }, - datum: %Datum{kind: :inline_datum, value: <<216, 121, 159, 1, 255>>}, + datum: %Datum{kind: :inline_datum, value: "D8799F01FF"}, reference_script: nil, value: %{ "lovelace" => 1_000_000 @@ -85,8 +85,8 @@ defmodule Sutra.Cardano.Transaction.OutputTest do }, stake_credential: nil }, - datum: %Datum{kind: :inline_datum, value: <<216, 121, 159, 1, 255>>}, - reference_script: "some-ref-script", + datum: %Datum{kind: :inline_datum, value: "D8799F01FF"}, + reference_script: "736F6D652D7265662D736372697074", value: %{ "lovelace" => 1_000_000 }