diff --git a/docs/api/plugins/aea_ledger_solana/account.md b/docs/api/plugins/aea_ledger_solana/account.md
index 83742f9a29..8be7d6b593 100644
--- a/docs/api/plugins/aea_ledger_solana/account.md
+++ b/docs/api/plugins/aea_ledger_solana/account.md
@@ -39,7 +39,7 @@ True if the `pubkey` can be loaded as a read-write account.
```python
@classmethod
-def from_solders(cls, meta: instruction.AccountMeta)
+def from_solders(cls, meta: AccountMeta)
```
Convert from a `solders` AccountMeta.
@@ -49,7 +49,7 @@ Convert from a `solders` AccountMeta.
#### to`_`solders
```python
-def to_solders() -> instruction.AccountMeta
+def to_solders() -> AccountMeta
```
Convert to a `solders` AccountMeta.
diff --git a/docs/api/plugins/aea_ledger_solana/crypto.md b/docs/api/plugins/aea_ledger_solana/crypto.md
index a365608480..9490509430 100644
--- a/docs/api/plugins/aea_ledger_solana/crypto.md
+++ b/docs/api/plugins/aea_ledger_solana/crypto.md
@@ -32,6 +32,17 @@ Instantiate a solana crypto object.
- `password`: the password to encrypt/decrypt the private key.
- `extra_entropy`: add extra randomness to whatever randomness from OS.
+
+
+#### pubkey
+
+```python
+@property
+def pubkey() -> Pubkey
+```
+
+Pubkey object.
+
#### private`_`key
diff --git a/docs/api/plugins/aea_ledger_solana/solana.md b/docs/api/plugins/aea_ledger_solana/solana.md
index 2b83273bec..81529dbaa4 100644
--- a/docs/api/plugins/aea_ledger_solana/solana.md
+++ b/docs/api/plugins/aea_ledger_solana/solana.md
@@ -28,6 +28,17 @@ Initialize the Solana ledger APIs.
- `kwargs`: keyword arguments
+
+
+#### api
+
+```python
+@property
+def api() -> SolanaApiClient
+```
+
+Get the underlying API object.
+
#### latest`_`hash
@@ -39,6 +50,99 @@ def latest_hash()
Get the latest hash.
+
+
+#### system`_`program
+
+```python
+@property
+def system_program() -> Pubkey
+```
+
+System program.
+
+
+
+#### sol`_`to`_`lamp
+
+```python
+@staticmethod
+def sol_to_lamp(sol: float) -> int
+```
+
+Solana to lamport value.
+
+
+
+#### to`_`account`_`meta
+
+```python
+@classmethod
+def to_account_meta(cls, pubkey: Union[Pubkey, str], is_signer: bool,
+ is_writable: bool) -> AccountMeta
+```
+
+To account meta.
+
+
+
+#### to`_`pubkey
+
+```python
+@staticmethod
+def to_pubkey(key: Union[SolanaCrypto, Keypair, Pubkey, str]) -> Pubkey
+```
+
+To pubkey.
+
+
+
+#### to`_`keypair
+
+```python
+@staticmethod
+def to_keypair(key: Union[SolanaCrypto, Keypair, str]) -> Pubkey
+```
+
+To keypair object.
+
+
+
+#### pda
+
+```python
+@staticmethod
+def pda(seeds: Sequence[bytes], program_id: Pubkey) -> Pubkey
+```
+
+Create TX PDA
+
+
+
+#### create`_`pda
+
+```python
+@staticmethod
+def create_pda(from_address: str, new_account_address: str, base_address: str,
+ seed: str, lamports: int, space: int, program_id: str)
+```
+
+Build a create pda transaction.
+
+**Arguments**:
+
+- `from_address`: the sender public key
+- `new_account_address`: the new account public key
+- `base_address`: base address
+- `seed`: seed
+- `lamports`: the amount of lamports to send
+- `space`: the space to allocate
+- `program_id`: the program id
+
+**Returns**:
+
+the tx, if present
+
#### wait`_`get`_`receipt
@@ -61,17 +165,6 @@ def construct_and_settle_tx(account1: SolanaCrypto, account2: SolanaCrypto,
Construct and settle a transaction.
-
-
-#### api
-
-```python
-@property
-def api() -> SolanaApiClient
-```
-
-Get the underlying API object.
-
#### update`_`with`_`gas`_`estimate
@@ -259,32 +352,6 @@ Build a create account transaction.
the tx, if present
-
-
-#### create`_`pda
-
-```python
-@staticmethod
-def create_pda(from_address: str, new_account_address: str, base_address: str,
- seed: str, lamports: int, space: int, program_id: str)
-```
-
-Build a create pda transaction.
-
-**Arguments**:
-
-- `from_address`: the sender public key
-- `new_account_address`: the new account public key
-- `base_address`: base address
-- `seed`: seed
-- `lamports`: the amount of lamports to send
-- `space`: the space to allocate
-- `program_id`: the program id
-
-**Returns**:
-
-the tx, if present
-
#### get`_`contract`_`instance
@@ -379,6 +446,67 @@ Prepare a transaction
the transaction
+
+
+#### build`_`instruction
+
+```python
+def build_instruction(
+ contract_instance: Program,
+ method_name: str,
+ data: List[Any],
+ accounts: Dict[str, Pubkey],
+ remaining_accounts: Optional[List[AccountMeta]] = None) -> JSONLike
+```
+
+Prepare an instruction
+
+
+
+#### serialize`_`tx
+
+```python
+def serialize_tx(
+ tx: Union[Dict, SolanaTransaction, SoldersTransaction,
+ SoldersVersionedTransaction]
+) -> Dict
+```
+
+Serialize transaction to solders transaction compatible json object.
+
+
+
+#### deserialize`_`tx
+
+```python
+def deserialize_tx(
+ tx: Union[Dict, SolanaTransaction, SoldersTransaction,
+ SoldersVersionedTransaction]
+) -> SolanaTransaction
+```
+
+Deserialize transaction to a solana transaction object.
+
+
+
+#### serialize`_`ix
+
+```python
+def serialize_ix(ix: Instruction) -> Dict
+```
+
+Serialize instruction.
+
+
+
+#### deserialize`_`ix
+
+```python
+def deserialize_ix(ix: Dict) -> Instruction
+```
+
+Deserialize instruction.
+
#### get`_`transaction`_`transfer`_`logs
diff --git a/packages/fetchai/skills/erc1155_client/skill.yaml b/packages/fetchai/skills/erc1155_client/skill.yaml
index 4d02a9cf39..f6b266cefc 100644
--- a/packages/fetchai/skills/erc1155_client/skill.yaml
+++ b/packages/fetchai/skills/erc1155_client/skill.yaml
@@ -21,7 +21,7 @@ fingerprint:
tests/test_strategy.py: bafybeicbxie3v6vue3gcnru6vsvggcgy3shxwrldis5gppizbuhooslcqa
fingerprint_ignore_patterns: []
connections:
-- valory/ledger:0.19.0:bafybeigdckv3e6bz6kfloz4ucqrsufft6k4jp6bwkbbcvh4fxvgbmzq3dm
+- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a
contracts:
- fetchai/erc1155:0.22.0:bafybeiff7a6xncyad53o2r7lekpnhexcspze6ocy55xtpzqeuacnlpunm4
protocols:
diff --git a/packages/fetchai/skills/erc1155_deploy/skill.yaml b/packages/fetchai/skills/erc1155_deploy/skill.yaml
index 89884f61e9..8544f858e2 100644
--- a/packages/fetchai/skills/erc1155_deploy/skill.yaml
+++ b/packages/fetchai/skills/erc1155_deploy/skill.yaml
@@ -21,7 +21,7 @@ fingerprint:
tests/test_strategy.py: bafybeigxtw2j2c7vl6xhdwos62jbtmx62xfgdyadptm5eewmkesmcooyea
fingerprint_ignore_patterns: []
connections:
-- valory/ledger:0.19.0:bafybeigdckv3e6bz6kfloz4ucqrsufft6k4jp6bwkbbcvh4fxvgbmzq3dm
+- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a
contracts:
- fetchai/erc1155:0.22.0:bafybeiff7a6xncyad53o2r7lekpnhexcspze6ocy55xtpzqeuacnlpunm4
protocols:
diff --git a/packages/fetchai/skills/generic_buyer/skill.yaml b/packages/fetchai/skills/generic_buyer/skill.yaml
index cf4928dd29..0615a422b9 100644
--- a/packages/fetchai/skills/generic_buyer/skill.yaml
+++ b/packages/fetchai/skills/generic_buyer/skill.yaml
@@ -19,7 +19,7 @@ fingerprint:
tests/test_models.py: bafybeibh72j3n72yseqvmpppucpu5wtidf6ebxbxkfnmrnlh4zv5y5apei
fingerprint_ignore_patterns: []
connections:
-- valory/ledger:0.19.0:bafybeigdckv3e6bz6kfloz4ucqrsufft6k4jp6bwkbbcvh4fxvgbmzq3dm
+- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a
contracts: []
protocols:
- fetchai/default:1.0.0:bafybeibtqp56jkijwjsohk4z5vqp6pfkiexmnmk5uleteotbsgrypy6gxm
diff --git a/packages/fetchai/skills/generic_seller/skill.yaml b/packages/fetchai/skills/generic_seller/skill.yaml
index 2756536b7a..8e7c882023 100644
--- a/packages/fetchai/skills/generic_seller/skill.yaml
+++ b/packages/fetchai/skills/generic_seller/skill.yaml
@@ -20,7 +20,7 @@ fingerprint:
tests/test_models.py: bafybeihabrc22zqssit3fmqhxptosy6qz6mx65ukhf5iayvirfv42xrhoq
fingerprint_ignore_patterns: []
connections:
-- valory/ledger:0.19.0:bafybeigdckv3e6bz6kfloz4ucqrsufft6k4jp6bwkbbcvh4fxvgbmzq3dm
+- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a
contracts: []
protocols:
- fetchai/default:1.0.0:bafybeibtqp56jkijwjsohk4z5vqp6pfkiexmnmk5uleteotbsgrypy6gxm
diff --git a/packages/packages.json b/packages/packages.json
index 25fda8a245..5b93c1bde5 100644
--- a/packages/packages.json
+++ b/packages/packages.json
@@ -8,7 +8,7 @@
"protocol/valory/http/1.0.0": "bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe",
"protocol/valory/ledger_api/1.0.0": "bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru",
"connection/fetchai/stub/0.21.0": "bafybeictgpdqbpyppmoxn2g7jkaxvulihew7zaszv4xyhgvsntq7tqs7wi",
- "connection/valory/ledger/0.19.0": "bafybeigdckv3e6bz6kfloz4ucqrsufft6k4jp6bwkbbcvh4fxvgbmzq3dm",
+ "connection/valory/ledger/0.19.0": "bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a",
"connection/valory/http_server/0.22.0": "bafybeid4nl6ruidpto3ynwjmc76nf42egcroqlhqq6krh2onwktu4ywpne",
"connection/valory/p2p_libp2p/0.1.0": "bafybeiaykya7tvir7k5scovjzuagpfcftvptxoi2od5qqqvukwglsrrtzy",
"connection/valory/p2p_libp2p_client/0.1.0": "bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq",
@@ -32,12 +32,12 @@
"connection/valory/http_client/0.23.0": "bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce",
"connection/valory/test_libp2p/0.1.0": "bafybeidy7qyswtj2fnh2q3qnusevamllw2ozzu723sh52r4k4gna3ig4e4",
"protocol/fetchai/tac/1.0.0": "bafybeiaukfwe7wbpikztprlmrfpphsxqpdzgamkbhvqyz54tl3k73kzsvi",
- "skill/fetchai/erc1155_client/0.28.0": "bafybeid3npgiuvgjyocxtxl6ovihrnicd5ezlim4aq4ytl3atnm5yywxmu",
- "skill/fetchai/erc1155_deploy/0.30.0": "bafybeie2lqwsqgpv35uy7nztohtukvogntsxqi74x37qsbsx7drgeajtau",
+ "skill/fetchai/erc1155_client/0.28.0": "bafybeiclxy64l364o7ek3imuwl4fnmtagy3j2coy6l7ga3gyt2lqzqifkq",
+ "skill/fetchai/erc1155_deploy/0.30.0": "bafybeiftychtjk7pz2ircduucnfpqpxduhk5ddvouzhkaq2vnfssozbgpa",
"skill/fetchai/error/0.17.0": "bafybeignei6feootyjzrqdt5j5yx7r4nrzuy6tdgdgsmrncldt5bud2dri",
"skill/fetchai/fipa_dummy_buyer/0.2.0": "bafybeid7rzqruvc3fkesueig2mbzy2qsfplieircyjzwbdl7c6q5eauiky",
- "skill/fetchai/generic_buyer/0.26.0": "bafybeibiplanh6h2biy27wt26jnzwftfsji77ajp26hcule5q2acjq3fjy",
- "skill/fetchai/generic_seller/0.27.0": "bafybeiboyk6q2sl6rdqvcksbg4gnfb766vpexrdcgjmxzm3kjmcsjnsvia",
+ "skill/fetchai/generic_buyer/0.26.0": "bafybeifyesl5ooduzfmjw4br2avinyxjbndiwsagwsjtxgrxtzchjyhcxy",
+ "skill/fetchai/generic_seller/0.27.0": "bafybeiablwq6oefmojsgj3yvedvo5b2bu4yosdr7k5cwn4xkcs4hxeb6fm",
"skill/fetchai/task_test_skill/0.1.0": "bafybeidv77u2xl52mnxakwvh7fuh46aiwfpteyof4eaptfd4agoi6cdble"
},
"third_party": {}
diff --git a/packages/valory/connections/ledger/connection.yaml b/packages/valory/connections/ledger/connection.yaml
index 972d97b552..f06122b914 100644
--- a/packages/valory/connections/ledger/connection.yaml
+++ b/packages/valory/connections/ledger/connection.yaml
@@ -16,7 +16,7 @@ fingerprint:
tests/conftest.py: bafybeid7vo7e2m76ey5beeadtbxywxx5ukefd5slwbc362rwmhht6i45ou
tests/test_contract_dispatcher.py: bafybeiag5lnpc7h25w23ash4hk4cowxsy5buxgpr474l3tfewnhf56eqyq
tests/test_ledger.py: bafybeigcedfr3yv3jse3xwrerrgwbelgb56uhgrvdus527d3daekh6dx4m
- tests/test_ledger_api.py: bafybeifwdpbds7ujd2uzxcapprdgdp5fn2gpbycsgbbefbsabrucnvrfiq
+ tests/test_ledger_api.py: bafybeifw5smawex5m2fm6rt4kmunc22kpabalmshh45qb3xnuap33sfgyi
fingerprint_ignore_patterns: []
connections: []
protocols:
diff --git a/packages/valory/connections/ledger/tests/test_ledger_api.py b/packages/valory/connections/ledger/tests/test_ledger_api.py
index bf1c203ec2..c7b85f2dfd 100644
--- a/packages/valory/connections/ledger/tests/test_ledger_api.py
+++ b/packages/valory/connections/ledger/tests/test_ledger_api.py
@@ -84,11 +84,12 @@
(EthereumCrypto.identifier, EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH).address),
],
)
+# TODO: uncomment gas station strategy config after the gasstation API start
gas_strategies = pytest.mark.parametrize(
"gas_strategies",
[
{"gas_price_strategy": None},
- {"gas_price_strategy": "gas_station"},
+ # {"gas_price_strategy": "gas_station"}, # noqa:E800
{"gas_price_strategy": "eip1559"},
{
"max_fee_per_gas": 1_000_000_000,
diff --git a/plugins/aea-ledger-solana/aea_ledger_solana/account.py b/plugins/aea-ledger-solana/aea_ledger_solana/account.py
index 9df4b84af9..0b52a656a2 100644
--- a/plugins/aea-ledger-solana/aea_ledger_solana/account.py
+++ b/plugins/aea-ledger-solana/aea_ledger_solana/account.py
@@ -19,7 +19,7 @@
"""Solana account implementation."""
from dataclasses import dataclass
-from solders import instruction
+from solders.instruction import AccountMeta
from solders.pubkey import Pubkey as PublicKey
@@ -35,7 +35,7 @@ class AccountMeta:
"""True if the `pubkey` can be loaded as a read-write account."""
@classmethod
- def from_solders(cls, meta: instruction.AccountMeta):
+ def from_solders(cls, meta: AccountMeta):
"""Convert from a `solders` AccountMeta."""
return cls(
pubkey=PublicKey.from_bytes(bytes(meta.pubkey)),
@@ -43,8 +43,8 @@ def from_solders(cls, meta: instruction.AccountMeta):
is_writable=meta.is_writable,
)
- def to_solders(self) -> instruction.AccountMeta:
+ def to_solders(self) -> AccountMeta:
"""Convert to a `solders` AccountMeta."""
- return instruction.AccountMeta(
+ return AccountMeta(
pubkey=self.pubkey, is_signer=self.is_signer, is_writable=self.is_writable
)
diff --git a/plugins/aea-ledger-solana/aea_ledger_solana/crypto.py b/plugins/aea-ledger-solana/aea_ledger_solana/crypto.py
index 0bce01ada7..ac57620211 100644
--- a/plugins/aea-ledger-solana/aea_ledger_solana/crypto.py
+++ b/plugins/aea-ledger-solana/aea_ledger_solana/crypto.py
@@ -27,8 +27,11 @@
import base58
from aea_ledger_solana.constants import _SOLANA
from cryptography.fernet import Fernet # type: ignore
+from solana.transaction import Transaction as SolanaTransaction
from solders.hash import Hash
+from solders.instruction import Instruction
from solders.keypair import Keypair
+from solders.pubkey import Pubkey
from solders.transaction import Transaction
from aea.common import JSONLike
@@ -60,6 +63,11 @@ def __init__(
extra_entropy=extra_entropy,
)
+ @property
+ def pubkey(self) -> Pubkey:
+ """Pubkey object."""
+ return self.entity.pubkey()
+
@property
def private_key(self) -> str:
"""
@@ -133,6 +141,32 @@ def sign_transaction(
"""
Sign a transaction in bytes string form.
+ :param transaction: the transaction to be signed
+ :param signers: list of signers
+ :return: signed transaction
+ """
+ if "ixs" in transaction:
+ return self._sign_ixs(ix_container=transaction)
+ return self._sign_tx_legacy(transaction=transaction, signers=signers)
+
+ def _sign_ixs(self, ix_container: JSONLike) -> JSONLike:
+ """Create a signed transaction from instructions."""
+ tx = SolanaTransaction(
+ fee_payer=self.entity.pubkey(),
+ recent_blockhash=Hash.from_string(ix_container["recent_blockhash"]),
+ instructions=[
+ Instruction.from_json(json.dumps(ix)) for ix in ix_container["ixs"]
+ ],
+ )
+ tx.sign(self.entity)
+ return json.loads(tx.to_solders().to_json())
+
+ def _sign_tx_legacy(
+ self, transaction: JSONLike, signers: Optional[list] = None
+ ) -> JSONLike:
+ """
+ Sign a transaction in bytes string form.
+
:param transaction: the transaction to be signed
:param signers: list of signers
:return: signed transaction
diff --git a/plugins/aea-ledger-solana/aea_ledger_solana/solana.py b/plugins/aea-ledger-solana/aea_ledger_solana/solana.py
index 07d389f7ed..76ef969906 100644
--- a/plugins/aea-ledger-solana/aea_ledger_solana/solana.py
+++ b/plugins/aea-ledger-solana/aea_ledger_solana/solana.py
@@ -20,7 +20,7 @@
import json
import logging
import time
-from typing import Any, Dict, List, Optional, Tuple
+from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, cast
from aea_ledger_solana.constants import (
DEFAULT_ADDRESS,
@@ -32,14 +32,21 @@
from aea_ledger_solana.faucet import SolanaFaucetApi # noqa: F401
from aea_ledger_solana.helper import SolanaHelper
from aea_ledger_solana.solana_api import SolanaApiClient
-from aea_ledger_solana.transaction import SolanaTransaction
+from aea_ledger_solana.transaction import (
+ SolanaTransaction,
+ SoldersTransaction,
+ SoldersVersionedTransaction,
+)
from aea_ledger_solana.transaction_instruction import TransactionInstruction
from anchorpy import Context, Idl, Program # type: ignore
from solana.blockhash import BlockhashCache
from solana.transaction import Transaction # type: ignore
from solders import system_program as ssp # type: ignore
-from solders.instruction import Instruction
-from solders.pubkey import Pubkey as PublicKey # type: ignore
+from solders.hash import Hash
+from solders.instruction import AccountMeta, Instruction
+from solders.keypair import Keypair
+from solders.pubkey import Pubkey # type: ignore
+from solders.pubkey import Pubkey as PublicKey
from solders.signature import Signature # type: ignore
from solders.system_program import ( # type: ignore; SYS_PROGRAM_ID,
CreateAccountParams,
@@ -88,12 +95,114 @@ def _get_latest_hash(self):
self._hash = blockhash["blockhash"]
self.BlockhashCache.set(blockhash=self._hash, slot=result.context.slot)
+ @property
+ def api(self) -> SolanaApiClient:
+ """Get the underlying API object."""
+ return self._api
+
@property
def latest_hash(self):
"""Get the latest hash."""
self._get_latest_hash()
return self._hash
+ @property
+ def system_program(self) -> Pubkey:
+ """System program."""
+ return SYS_PROGRAM_ID
+
+ @staticmethod
+ def sol_to_lamp(sol: float) -> int:
+ """Solana to lamport value."""
+ return int(sol * 1000000000)
+
+ @classmethod
+ def to_account_meta(
+ cls,
+ pubkey: Union[Pubkey, str],
+ is_signer: bool,
+ is_writable: bool,
+ ) -> AccountMeta:
+ """To account meta."""
+ return AccountMeta(
+ pubkey=cls.to_pubkey(pubkey),
+ is_signer=is_signer,
+ is_writable=is_writable,
+ )
+
+ @staticmethod
+ def to_pubkey(key: Union[SolanaCrypto, Keypair, Pubkey, str]) -> Pubkey:
+ """To pubkey."""
+ if isinstance(key, Pubkey):
+ return key
+ if isinstance(key, Keypair):
+ return key.pubkey()
+ if isinstance(key, SolanaCrypto):
+ return key.entity.pubkey()
+ try:
+ return Pubkey.from_string(key)
+ except BaseException:
+ return Keypair.from_base58_string(key).pubkey()
+
+ @staticmethod
+ def to_keypair(key: Union[SolanaCrypto, Keypair, str]) -> Pubkey:
+ """To keypair object."""
+ if isinstance(key, Keypair):
+ return key
+ if isinstance(key, SolanaCrypto):
+ return key.entity
+ return Keypair.from_base58_string(key).pubkey()
+
+ @staticmethod
+ def pda(
+ seeds: Sequence[bytes],
+ program_id: Pubkey,
+ ) -> Pubkey:
+ """Create TX PDA"""
+ pda, _ = Pubkey.find_program_address(
+ seeds=seeds,
+ program_id=program_id,
+ )
+ return pda
+
+ @staticmethod
+ def create_pda(
+ from_address: str,
+ new_account_address: str,
+ base_address: str,
+ seed: str,
+ lamports: int,
+ space: int,
+ program_id: str,
+ ):
+ """
+ Build a create pda transaction.
+
+ :param from_address: the sender public key
+ :param new_account_address: the new account public key
+ :param base_address: base address
+ :param seed: seed
+ :param lamports: the amount of lamports to send
+ :param space: the space to allocate
+ :param program_id: the program id
+ :return: the tx, if present
+ """
+ params = CreateAccountWithSeedParams(
+ PublicKey(from_address),
+ PublicKey(new_account_address),
+ PublicKey(base_address),
+ seed,
+ lamports,
+ space,
+ PublicKey(program_id),
+ )
+ createPDAInstruction = TransactionInstruction.from_solders(
+ ssp.create_account_with_seed(params.to_solders())
+ )
+ txn = Transaction().add(createPDAInstruction)
+ tx = txn._solders.to_json() # pylint: disable=protected-access
+ return json.loads(tx)
+
def wait_get_receipt(
self, transaction_digest: str
) -> Tuple[Optional[JSONLike], bool]:
@@ -140,11 +249,6 @@ def construct_and_settle_tx(
return transaction_digest, transaction_receipt, is_settled
- @property
- def api(self) -> SolanaApiClient:
- """Get the underlying API object."""
- return self._api
-
def update_with_gas_estimate(self, transaction: JSONLike) -> JSONLike:
"""
Attempts to update the transaction with a gas estimate
@@ -295,8 +399,7 @@ def _try_send_signed_transaction(
`raise_on_try`: bool flag specifying whether the method will raise or log on error (used by `try_decorator`)
:return: tx_digest, if present
"""
-
- stxn = SolanaTransaction.from_json(tx_signed)
+ stxn = self.deserialize_tx(tx=tx_signed)
txn_resp = self._api.send_raw_transaction(bytes(stxn.serialize()))
retries = 2
while True and retries > 0:
@@ -426,44 +529,6 @@ def create_default_account(
tx = txn._solders.to_json() # pylint: disable=protected-access
return json.loads(tx)
- @staticmethod
- def create_pda(
- from_address: str,
- new_account_address: str,
- base_address: str,
- seed: str,
- lamports: int,
- space: int,
- program_id: str,
- ):
- """
- Build a create pda transaction.
-
- :param from_address: the sender public key
- :param new_account_address: the new account public key
- :param base_address: base address
- :param seed: seed
- :param lamports: the amount of lamports to send
- :param space: the space to allocate
- :param program_id: the program id
- :return: the tx, if present
- """
- params = CreateAccountWithSeedParams(
- PublicKey(from_address),
- PublicKey(new_account_address),
- PublicKey(base_address),
- seed,
- lamports,
- space,
- PublicKey(program_id),
- )
- createPDAInstruction = TransactionInstruction.from_solders(
- ssp.create_account_with_seed(params.to_solders())
- )
- txn = Transaction().add(createPDAInstruction)
- tx = txn._solders.to_json() # pylint: disable=protected-access
- return json.loads(tx)
-
def get_contract_instance(
self, contract_interface: Dict[str, str], contract_address: Optional[str] = None
) -> Any:
@@ -589,22 +654,95 @@ def build_transaction( # pylint: disable=too-many-arguments
"""
if method_args is None:
raise ValueError("`method_args` can not be None")
-
if method_args["data"] is None:
raise ValueError("Data is required")
if method_args["accounts"] is None:
raise ValueError("Accounts are required")
- if "remaining_accounts" not in method_args:
- method_args["remaining_accounts"] = None
+ if tx_args.get("instruction_only", False):
+ return self.build_instruction(
+ contract_instance=contract_instance,
+ method_name=method_name,
+ data=method_args["data"],
+ accounts=method_args["accounts"],
+ remaining_accounts=method_args.get("remaining_accounts"),
+ )
+ tx = contract_instance.transaction[method_name](
+ *method_args["data"],
+ ctx=Context(
+ accounts=method_args["accounts"],
+ remaining_accounts=method_args.get("remaining_accounts"),
+ ),
+ payer=tx_args.get("payer"),
+ blockhash=Hash.from_string(self.latest_hash),
+ )
+ return self.serialize_tx(tx=tx)
+
+ def build_instruction( # pylint: disable=too-many-arguments
+ self,
+ contract_instance: Program,
+ method_name: str,
+ data: List[Any],
+ accounts: Dict[str, Pubkey],
+ remaining_accounts: Optional[List[AccountMeta]] = None,
+ ) -> JSONLike:
+ """Prepare an instruction"""
+ return self.serialize_ix(
+ contract_instance.methods[method_name]
+ .args(arguments=data)
+ .accounts(accs=accounts)
+ .remaining_accounts(accounts=remaining_accounts or [])
+ .instruction()
+ )
- data = method_args["data"]
- accounts = method_args["accounts"]
- remaining_accounts = method_args["remaining_accounts"]
+ def serialize_tx(
+ self,
+ tx: Union[
+ Dict, SolanaTransaction, SoldersTransaction, SoldersVersionedTransaction
+ ],
+ ) -> Dict:
+ """Serialize transaction to solders transaction compatible json object."""
+ if isinstance(tx, Dict):
+ return tx
+ if isinstance(tx, SolanaTransaction):
+ return json.loads(cast(SolanaTransaction, tx).to_solders().to_json())
+ if isinstance(tx, SoldersTransaction):
+ return json.loads(cast(SoldersTransaction, tx).to_json())
+ if isinstance(tx, SoldersVersionedTransaction):
+ return json.loads(
+ cast(SoldersVersionedTransaction, tx)
+ .into_legacy_transaction()
+ .to_json()
+ )
+ raise ValueError(f"Unknown transction type found `{type(tx)}`")
- txn = contract_instance.transaction[method_name](
- *data, ctx=Context(accounts=accounts, remaining_accounts=remaining_accounts)
+ def deserialize_tx(
+ self,
+ tx: Union[
+ Dict, SolanaTransaction, SoldersTransaction, SoldersVersionedTransaction
+ ],
+ ) -> SolanaTransaction:
+ """Deserialize transaction to a solana transaction object."""
+ if isinstance(tx, SolanaTransaction):
+ return cast(SolanaTransaction, tx)
+ if isinstance(tx, SoldersTransaction):
+ return SolanaTransaction.from_solders(txn=tx)
+ if isinstance(tx, SoldersVersionedTransaction):
+ return SolanaTransaction.from_solders(txn=tx.into_legacy_transaction())
+ if not isinstance(tx, Dict):
+ raise ValueError(f"Unknown transction type found `{type(tx)}`")
+
+ # TODO: Safeguard for tx serialized to solders
+ return SolanaTransaction.from_solders(
+ SoldersTransaction.from_json(json.dumps(tx))
)
- return json.loads(txn.to_solders().to_json())
+
+ def serialize_ix(self, ix: Instruction) -> Dict:
+ """Serialize instruction."""
+ return json.loads(ix.to_json())
+
+ def deserialize_ix(self, ix: Dict) -> Instruction:
+ """Deserialize instruction."""
+ return Instruction.from_json(json.dumps(ix))
def get_transaction_transfer_logs( # pylint: disable=too-many-arguments,too-many-locals
self,
diff --git a/plugins/aea-ledger-solana/aea_ledger_solana/transaction.py b/plugins/aea-ledger-solana/aea_ledger_solana/transaction.py
index 97a515dea5..0e4686d9da 100644
--- a/plugins/aea-ledger-solana/aea_ledger_solana/transaction.py
+++ b/plugins/aea-ledger-solana/aea_ledger_solana/transaction.py
@@ -21,6 +21,10 @@
from solana.transaction import Transaction
from solders.transaction import Transaction as SoldersTransaction
+from solders.transaction import VersionedTransaction as BaseSoldersVersionedTransaction
+
+
+SoldersVersionedTransaction = BaseSoldersVersionedTransaction
class SolanaTransaction(Transaction):
diff --git a/tox.ini b/tox.ini
index e53e5627d4..d9f49d814b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -255,6 +255,7 @@ commands =
python -m pip install --no-deps file://{toxinidir}/plugins/aea-cli-ipfs
aea packages lock
aea --registry-path=./tests/data/packages packages lock
+ python {toxinidir}/scripts/check_doc_ipfs_hashes.py --fix
[testenv:package-version-checks]
skipsdist = True