defmodule NearApi.Transaction do
@moduledoc """
Create NEAR [transactions](https://docs.near.org/docs/tutorials/create-transactions) here
"""
require Logger
@type t :: %__MODULE__{
signer_id: String.t(),
receiver_id: String.t(),
nonce: integer,
public_key: NearApi.PublicKey.t(),
block_hash: binary,
actions: [NearApi.Action.t()]
}
use Borsh,
schema: [
signer_id: :string,
public_key: :borsh,
nonce: :u64,
receiver_id: :string,
block_hash: [32],
actions: [:borsh]
]
defstruct [
:signer_id,
:public_key,
:nonce,
:receiver_id,
:block_hash,
:actions
]
@doc """
Creates a NearApi.Transaction struct, not serialized
Parameters:
`from_account` - an account strut NearApi.Account where `account_id` and `key_pair`
`receiver_id` - NEAR account ID who we are sending tokens, e.g. `helloworld.near`
`actions` - a list of transaction actions, e.g. NearApi.Actions.FunctionCall or NearApi.Actions.Transfer
"""
@spec create_transaction(from_account :: NearApi.Account.t(), receiver_id :: String.t(), actions :: list) ::
{:ok, NearApi.Transaction.t()} | {:error, :error_retrieving_access_key}
def create_transaction(from_account, receiver_id, actions) do
public_key = from_account.key_pair.public_key
public_key_encoded = B58.encode58(from_account.key_pair.public_key.data)
account_id = from_account.account_id
with {:ok, key} <- NearApi.RPC.AccessKeys.view_access_key(account_id, nil, public_key_encoded) do
block_hash_raw = key["result"]["block_hash"]
nonce = key["result"]["nonce"] + 1
block_hash = B58.decode58!(block_hash_raw)
{:ok,
%NearApi.Transaction{
signer_id: account_id,
receiver_id: receiver_id,
nonce: nonce,
public_key: public_key,
block_hash: block_hash,
actions: actions
}}
else
error ->
Logger.error("#{__MODULE__}: Cannot retrieve access key: #{inspect(error)}")
{:error, :error_retrieving_access_key}
end
end
def sign_and_serialise(tx, key_pair) do
serialised_tx = borsh_encode(tx)
serialized_tx_hash = :crypto.hash(:sha256, serialised_tx)
signature = NearApi.KeyPair.signature(serialized_tx_hash, key_pair)
st = %NearApi.SignedTransaction{transaction: tx, signature: %NearApi.Signature{key_type: 0, data: signature}}
NearApi.SignedTransaction.borsh_encode(st)
end
def payload(tx, key_pair) do
tx
|> sign_and_serialise(key_pair)
|> Base.encode64(padding: false)
end
end