Skip to content

Commit

Permalink
Refactor the python code (#22)
Browse files Browse the repository at this point in the history
* Update readme

* 🔨 Refactor tests
  • Loading branch information
nagdahimanshu authored Jun 4, 2024
1 parent f5cc31b commit 5e88310
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 795 deletions.
25 changes: 17 additions & 8 deletions PLUGIN_SPECIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

Smart contracts covered by this plugin are:

| Network | Version | Smart Contract | Address |
| -------------------- | ------- | -------------- | -------------------------------------------- |
| Lisk Sepolia Testnet | - | TokenClaim | `0x3D4190b08E3E30183f5AdE3A116f2534Ee3a4f94` |
| Lisk Sepolia Testnet | - | Reward | `0xFd322B4724C497E59D48fff8f79c16b4D48837f5` |
| Lisk Sepolia Testnet | - | Airdrop | `0x9fA3CA453EbfB7a6d1085153D83a2988eE822BD0` |
| Lisk Mainnet | - | TokenClaim | `0xD7BE2Fd98BfD64c1dfCf6c013fC593eF09219994` |
| Lisk Mainnet | - | Reward | `0xD35ca9577a9DADa7624a35EC10C2F55031f0Ab1f` |
| Lisk Mainnet | - | Airdrop | `TODO` |
| Network | Version | Smart Contract | Address |
| -------------------- | ------- | -------------- | ------------------------------------------------ |
| Lisk Sepolia Testnet | - | TokenClaim | `0x3D4190b08E3E30183f5AdE3A116f2534Ee3a4f94` |
| Lisk Sepolia Testnet | - | Reward | `0xFd322B4724C497E59D48fff8f79c16b4D48837f5` |
| Lisk Sepolia Testnet | - | Airdrop | `0x9fA3CA453EbfB7a6d1085153D83a2988eE822BD0` |
| Lisk Sepolia Testnet | - | Governor | `0xf9181aaD773d423A2cc0155Cb4263E563D51B467` |
| Lisk Mainnet | - | TokenClaim | `0xD7BE2Fd98BfD64c1dfCf6c013fC593eF09219994` |
| Lisk Mainnet | - | Reward | `0xD35ca9577a9DADa7624a35EC10C2F55031f0Ab1f` |
| Lisk Mainnet | - | Airdrop | `TODO` |
| Lisk Mainnet | - | Governor | `0x58a61b1807a7bDA541855DaAEAEe89b1DDA48568` |


## Functions

Expand All @@ -28,4 +31,10 @@ Following functions are covered by this plugins:
| Reward | resumeUnlockingCountdown | `0x82d4ae58` | <table> <tbody> <tr><td><code>uint256[] lockIDs</code></td></tr> </tbody> </table> |
| Reward | increaseLockingAmount | `0xf94415ca` | <table> <tbody> <tr><td><code>(uint256 lockID, uint256 amountIncrease)[]</code></td></tr> </tbody> </table> |
| Reward | extendDuration | `0x2d412a71` | <table> <tbody> <tr><td><code>(uint256 lockID, uint256 durationExtension)[]</code></td></tr> </tbody> </table> |
| Reward | deletePositions | `0x221b2b41` | <table> <tbody> <tr><td><code>uint256[] lockIDs</code></td></tr> </tbody> </table> |
| Reward | addUnusedRewards | `0x315d4222` | <table> <tbody> <tr><td><code>uint256 amount</code></td></tr> <tr><td><code>uint256 duration</code></td></tr> <tr><td><code>uint256 delay</code></td></tr> </tbody> </table> |
| Reward | fundStakingRewards | `0xebcb3818` | <table> <tbody> <tr><td><code>uint256 amount</code></td></tr> <tr><td><code>uint256 duration</code></td></tr> <tr><td><code>uint256 delay</code></td></tr> </tbody> </table> |
| Airdrop | claimAirdrop | `0x0c1646b7` | <table> <tbody> <tr><td><code>uint256 claimAmount</code></td></tr> <tr><td><code>bytes liskAddress</code></td></tr> </tbody> </table> |
| Governor | propose | `0x7d5e81e2` | <table> <tbody> <tr><td><code>address[] targets</code></td></tr> <tr><td><code>uint256[] values</code></td></tr> </tbody> </table> |
| Governor | castVote | `0x56781388` | <table> <tbody> <tr><td><code>uint256 proposalId</code></td></tr> <tr><td><code>uint256 support</code></td></tr> </tbody> </table> |
| Governor | castVoteWithReason | `0x7b3c71d3` | <table> <tbody> <tr><td><code>uint256 proposalId</code></td></tr> <tr><td><code>uint256 support</code></td></tr> <tr><td><code>string reason</code></td></tr> </tbody> </table> |
1 change: 0 additions & 1 deletion src/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
X(REWARD_DELETE_POSITIONS, 0x221b2b41) \
X(REWARD_ADD_UNUSED_REWARDS, 0x315d4222) \
X(REWARD_FUND_STAKING_REWARDS, 0xebcb3818) \
X(REWARD_Extend_Duration, 0x2d412a71) \
X(CLAIM_AIRDROP, 0x0c1646b7) \
X(GOVERNOR_PROPOSE, 0x7d5e81e2) \
X(GOVERNOR_CAST_VOTE, 0x56781388) \
Expand Down
11 changes: 2 additions & 9 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
# Tests

This directory contains non-regression tests for the Boilerplate plugin.
This directory contains non-regression tests for the Lisk App Plugin.
The tests craft APDUs, send them to the application, and assert the RAPDUs results and the screen content.
You will need to adapt / enrich the test database with tests relevant to your plugin.
The presence of functional testing of your plugin and an associated CI is mandatory.

The [Speculos](https://github.com/LedgerHQ/speculos) tool is used to emulate the device and its applications.
The [Ragger](https://github.com/LedgerHQ/ragger) test framework (pytest based) is used to manage the Speculos instance and provide useful helper functions (APDU exchanges, screen navigation, etc).
Both framework are developed by Ledger, if you have trouble using them, we invite you to get in touch with us on our [Discord](https://developers.ledger.com/contact/).
For this reason, the usage of the Ragger framework for your tests is greatly recommended.


## Binaries

Expand All @@ -28,12 +23,10 @@ Example of the correct file tree with Ethereum compiled for all targets.
The first method is to use the Ledger VSCode extension to automatically manage dependencies
The second method is to go in the Ethereum project, compile the application, and dispatch the `build/` output directory.
A third method is to re-use the Ethereum build used in the CI, and available as artifact.
For example in the [plugin-boilerplate CI](https://github.com/LedgerHQ/app-plugin-boilerplate/actions/workflows/build_and_functional_tests.yml).


## Launching the tests

The plugin boilerplate app comes with functional tests
The Lisk App Plugin comes with functional tests


### macOS / Windows
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
73 changes: 6 additions & 67 deletions tests/test_airdrop.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
from pathlib import Path
import json
import os
import datetime

from hexbytes import HexBytes

from web3 import Web3
from eth_typing import ChainId

from ledger_app_clients.ethereum.client import EthAppClient
import ledger_app_clients.ethereum.response_parser as ResponseParser
from ledger_app_clients.ethereum.utils import get_selector_from_data, recover_transaction
from ragger.navigator import NavInsID

from .utils import get_appname_from_makefile, DERIVATION_PATH

from .utils import run_test, load_contract

ROOT_SCREENSHOT_PATH = Path(__file__).parent
ABIS_FOLDER = "%s/abis" % (os.path.dirname(__file__))

PLUGIN_NAME = get_appname_from_makefile()

# TODO: Update address with abi
with open("%s/0x9fA3CA453EbfB7a6d1085153D83a2988eE822BD0.abi.json" % (ABIS_FOLDER)) as file:
contract = Web3().eth.contract(
abi=json.load(file),
# Get address from filename
address=bytes.fromhex(os.path.basename(file.name).split(".")[0].split("x")[-1])
)
contract = load_contract(
"9fA3CA453EbfB7a6d1085153D83a2988eE822BD0",
"airdrop"
)

def test_claim_airdrop(backend, firmware, navigator, test_name, wallet_addr):
client = EthAppClient(backend)

data = contract.encodeABI("claimAirdrop", [
bytes.fromhex("77abc2dd8ca5021dbb8e91e63f574b1e440764d2"),
4915507196,
Expand All @@ -40,40 +15,4 @@ def test_claim_airdrop(backend, firmware, navigator, test_name, wallet_addr):
]
])

# first setup the external plugin
client.set_external_plugin(PLUGIN_NAME,
contract.address,
# Extract function selector from the encoded data
get_selector_from_data(data))

tx_params = {
"nonce": 20,
"maxFeePerGas": Web3.to_wei(145, "gwei"),
"maxPriorityFeePerGas": Web3.to_wei(1.5, "gwei"),
"gas": 173290,
"to": contract.address,
"value": Web3.to_wei(0.1, "ether"),
"chainId": ChainId.ETH,
"data": data
}

# send the transaction
with client.sign(DERIVATION_PATH, tx_params):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Accept",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# verify signature
vrs = ResponseParser.signature(client.response().data)
addr = recover_transaction(tx_params, vrs)
assert addr == wallet_addr.get()
run_test(contract, data, backend, firmware, navigator, test_name, wallet_addr)
113 changes: 7 additions & 106 deletions tests/test_claim.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
from pathlib import Path
import json
import os
import datetime

from hexbytes import HexBytes

from web3 import Web3
from eth_typing import ChainId

from ledger_app_clients.ethereum.client import EthAppClient
import ledger_app_clients.ethereum.response_parser as ResponseParser
from ledger_app_clients.ethereum.utils import get_selector_from_data, recover_transaction
from ragger.navigator import NavInsID

from .utils import get_appname_from_makefile, DERIVATION_PATH


ROOT_SCREENSHOT_PATH = Path(__file__).parent
ABIS_FOLDER = "%s/abis" % (os.path.dirname(__file__))

PLUGIN_NAME = get_appname_from_makefile()
from .utils import run_test, load_contract


with open("%s/0xD7BE2Fd98BfD64c1dfCf6c013fC593eF09219994.abi.json" % (ABIS_FOLDER)) as file:
contract = Web3().eth.contract(
abi=json.load(file),
# Get address from filename
address=bytes.fromhex(os.path.basename(file.name).split(".")[0].split("x")[-1])
)
contract = load_contract(
"D7BE2Fd98BfD64c1dfCf6c013fC593eF09219994",
"claim"
)

def test_claim_regular_account(backend, firmware, navigator, test_name, wallet_addr):
client = EthAppClient(backend)

data = contract.encodeABI("claimRegularAccount", [
[
bytes.fromhex("9ca797d905e78f38685b61f62521632ef486bc6ce3e707d2af41b7fe146303c1"),
Expand All @@ -50,47 +25,9 @@ def test_claim_regular_account(backend, firmware, navigator, test_name, wallet_a
)
])

# first setup the external plugin
client.set_external_plugin(PLUGIN_NAME,
contract.address,
# Extract function selector from the encoded data
get_selector_from_data(data))

tx_params = {
"nonce": 20,
"maxFeePerGas": Web3.to_wei(145, "gwei"),
"maxPriorityFeePerGas": Web3.to_wei(1.5, "gwei"),
"gas": 173290,
"to": contract.address,
"value": Web3.to_wei(0.1, "ether"),
"chainId": ChainId.ETH,
"data": data
}

# send the transaction
with client.sign(DERIVATION_PATH, tx_params):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Accept",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# verify signature
vrs = ResponseParser.signature(client.response().data)
addr = recover_transaction(tx_params, vrs)
assert addr == wallet_addr.get()
run_test(contract, data, backend, firmware, navigator, test_name, wallet_addr)

def test_claim_multisig_account(backend, firmware, navigator, test_name, wallet_addr):
client = EthAppClient(backend)

data = contract.encodeABI("claimMultisigAccount", [
[
bytes.fromhex("f90c3db9f834e9a33086969313a1f5aa2288933e69a065cb829ab7524f113340"),
Expand All @@ -116,40 +53,4 @@ def test_claim_multisig_account(backend, firmware, navigator, test_name, wallet_
]
])

# first setup the external plugin
client.set_external_plugin(PLUGIN_NAME,
contract.address,
# Extract function selector from the encoded data
get_selector_from_data(data))

tx_params = {
"nonce": 20,
"maxFeePerGas": Web3.to_wei(145, "gwei"),
"maxPriorityFeePerGas": Web3.to_wei(1.5, "gwei"),
"gas": 173290,
"to": contract.address,
"value": Web3.to_wei(0.1, "ether"),
"chainId": ChainId.ETH,
"data": data
}

# send the transaction
with client.sign(DERIVATION_PATH, tx_params):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Accept",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# verify signature
vrs = ResponseParser.signature(client.response().data)
addr = recover_transaction(tx_params, vrs)
assert addr == wallet_addr.get()
run_test(contract, data, backend, firmware, navigator, test_name, wallet_addr)
Loading

0 comments on commit 5e88310

Please sign in to comment.