diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6250ca0..6a906e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,5 +12,9 @@ jobs: - name: Builds the Docker image run: docker build ./ -t velodrome/sugar - - name: Runs code QA and tests - run: docker run --rm --env-file=env.example -v $(pwd):/app -w /app -t velodrome/sugar sh -c 'flake8 && brownie test --network=optimism-main' + - name: Runs code QA and tests for optimism + run: docker run --rm --env-file=env.example -v $(pwd):/app -w /app -t velodrome/sugar sh -c 'flake8 && brownie test tests/optimism/**.py --network=optimism-main' + - name: Runs code QA and tests for base + run: docker run --rm --env-file=env.example -v $(pwd):/app -w /app -t velodrome/sugar sh -c 'flake8 && brownie test tests/base/**.py --network=base-main' + - name: Runs code QA and sugar factory registry tests + run: docker run --rm --env-file=env.example -v $(pwd):/app -w /app -t velodrome/sugar sh -c 'flake8 && brownie test tests/test_factory_registry.py' diff --git a/Dockerfile b/Dockerfile index 17d4da6..2da31c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,3 +13,8 @@ RUN pip install -r requirements.txt RUN brownie networks modify optimism-test host=https://sepolia.optimism.io RUN brownie networks modify optimism-main host=https://optimism-mainnet.wallet.coinbase.com + +RUN brownie networks modify base-main host=https://mainnet.base.org + +RUN brownie networks add Bob bob-main host=https://rpc.gobob.xyz/ chainid=60808 +RUN brownie networks add Mode mode-main host=https://mainnet.mode.network chainid=34443 diff --git a/env.example b/env.example index 2539075..7acdac0 100644 --- a/env.example +++ b/env.example @@ -1,44 +1,61 @@ -VOTER_ADDRESS=0x41C914ee0c7E1A5edCD0295623e6dC557B5aBf3C -DIST_ADDRESS=0x9D4736EC60715e71aFe72973f7885DCBC21EA99b -GOVERNOR_ADDRESS=0x1F82e10D58aEf03DeA2e478029fB0387A1cbE989 -RELAY_REGISTRY_ADDRESSES=0xe9F00f2e61CB0c6fb00A2e457546aCbF0fC303C2,0x6b1253B116B5919932399295C75116d33F8EfF96 - -LP_SUGAR_ADDRESS=0x0937DA94887472239Ada5483c6DBd2904FfD4ACF -VE_SUGAR_ADDRESS=0x94f913362b232e31daB49a1aFB775cfd25DaA6a1 -RELAY_SUGAR_ADDRESS=0xb8307e5842B9aeE75C704183F0355076aa74b4e2 - # For testing purposes TEST_FACTORY_ADDRESS=0xCc0bDDB707055e04e497aB22a59c2aF4391cd12F TEST_ADDRESS=0xEeE7FB850D28f5cabd5f1EDF540646b5bEA17CE5 TEST_ALM_ADDRESS=0x892Ff98a46e5bd141E2D12618f4B2Fe6284debac -CHAIN=optimism +CHAIN_ID=10 CONTRACT='lp' #OPTIMISM -OPTIMISM_REGISTRY=0xF4c67CdEAaB8360370F41514d06e32CcD8aA1d7B -OPTIMISM_VOTER=0x41C914ee0c7E1A5edCD0295623e6dC557B5aBf3C -OPTIMISM_CONVERTOR=0x585Af0b397AC42dbeF7f18395426BF878634f18D -OPTIMISM_SLIPSTREAM_HELPER=0x5Bd7E2221C2d59c99e6A9Cd18D80A5F4257D0f32 -OPTIMISM_ALM_FACTORY=0xeD8b81E3fF6c54951621715F5992CA52007D88bA +VOTER_10=0x41C914ee0c7E1A5edCD0295623e6dC557B5aBf3C +REGISTRY_10=0xF4c67CdEAaB8360370F41514d06e32CcD8aA1d7B +CONVERTOR_10=0x585Af0b397AC42dbeF7f18395426BF878634f18D +SLIPSTREAM_HELPER_10=0x5Bd7E2221C2d59c99e6A9Cd18D80A5F4257D0f32 +ALM_FACTORY_10=0xeD8b81E3fF6c54951621715F5992CA52007D88bA +DIST_10=0x9D4736EC60715e71aFe72973f7885DCBC21EA99b +RELAY_REGISTRY_ADDRESSES_10=0xe9F00f2e61CB0c6fb00A2e457546aCbF0fC303C2,0x6b1253B116B5919932399295C75116d33F8EfF96 +GOVERNOR_10=0x1F82e10D58aEf03DeA2e478029fB0387A1cbE989 + +LP_SUGAR_ADDRESS_10=0x0937DA94887472239Ada5483c6DBd2904FfD4ACF +VE_SUGAR_ADDRESS_10=0x94f913362b232e31daB49a1aFB775cfd25DaA6a1 +RELAY_SUGAR_ADDRESS_10=0xb8307e5842B9aeE75C704183F0355076aa74b4e2 #BASE -BASE_REGISTRY=0x5C3F18F06CC09CA1910767A34a20F771039E37C0 -BASE_VOTER=0x16613524e02ad97eDfeF371bC883F2F5d6C480A5 -BASE_CONVERTOR=0x1111111111111111111111111111111111111111 -BASE_SLIPSTREAM_HELPER=0x6d2D739bf37dFd93D804523c2dfA948EAf32f8E1 -BASE_ALM_FACTORY=0x5B1b1aaC71bDca9Ed1dCb2AA357f678584db4029 +VOTER_8453=0x16613524e02ad97eDfeF371bC883F2F5d6C480A5 +REGISTRY_8453=0x5C3F18F06CC09CA1910767A34a20F771039E37C0 +CONVERTOR_8453=0x1111111111111111111111111111111111111111 +SLIPSTREAM_HELPER_8453=0x6d2D739bf37dFd93D804523c2dfA948EAf32f8E1 +ALM_FACTORY_8453=0x5B1b1aaC71bDca9Ed1dCb2AA357f678584db4029 +DIST_8453=0x227f65131A261548b057215bB1D5Ab2997964C7d +RELAY_REGISTRY_ADDRESSES_8453=0x05e41604B9463e2224227053980dfF3f57fb6dB5,0xD308aBCe663302d3b86b36d332CEFd8A4F62C5Ed +GOVERNOR_8453=0x94C012A23A8A65A6f40608dA30534a46a433F410 + +LP_SUGAR_ADDRESS_8453=0x51f290CCCD6a54Af00b38edDd59212dE068B8A4b +VE_SUGAR_ADDRESS_8453=0x4c5d3925fe65DFeB5A079485136e4De09cb664A5 +RELAY_SUGAR_ADDRESS_8453=0x8932B5FE23C07Df06533F8f09E43e7cca6a24143 #MODE -MODE_REGISTRY=0x0000000000000000000000000000000000000000 -MODE_VOTER=0x0000000000000000000000000000000000000000 -MODE_CONVERTOR=0x1111111111111111111111111111111111111111 -MODE_SLIPSTREAM_HELPER=0x0000000000000000000000000000000000000000 -MODE_ALM_FACTORY=0x0000000000000000000000000000000000000000 +VOTER_34443=0x0000000000000000000000000000000000000000 +REGISTRY_34443=0x7e9f5D93C590c45A54faC774baf9AdD6CA94a295 +CONVERTOR_34443=0x1111111111111111111111111111111111111111 +SLIPSTREAM_HELPER_34443=0x0000000000000000000000000000000000000000 +ALM_FACTORY_34443=0x0000000000000000000000000000000000000000 +DIST_34443=0x0000000000000000000000000000000000000000 +RELAY_REGISTRY_ADDRESSES_34443= + +LP_SUGAR_ADDRESS_34443= +VE_SUGAR_ADDRESS_34443= +RELAY_SUGAR_ADDRESS_34443= #BOB -BOB_REGISTRY=0x0000000000000000000000000000000000000000 -BOB_VOTER=0x0000000000000000000000000000000000000000 -BOB_CONVERTOR=0x1111111111111111111111111111111111111111 -BOB_SLIPSTREAM_HELPER=0x0000000000000000000000000000000000000000 -BOB_ALM_FACTORY=0x0000000000000000000000000000000000000000 +VOTER_60808=0x0000000000000000000000000000000000000000 +REGISTRY_60808=0x0000000000000000000000000000000000000000 +CONVERTOR_60808=0x1111111111111111111111111111111111111111 +SLIPSTREAM_HELPER_60808=0x0000000000000000000000000000000000000000 +ALM_FACTORY_60808=0x0000000000000000000000000000000000000000 +DIST_60808=0x0000000000000000000000000000000000000000 +RELAY_REGISTRY_ADDRESSES_60808= + +LP_SUGAR_ADDRESS_60808= +VE_SUGAR_ADDRESS_60808= +RELAY_SUGAR_ADDRESS_60808= diff --git a/tests/base/test_lp_sugar.py b/tests/base/test_lp_sugar.py new file mode 100644 index 0000000..e8c4e15 --- /dev/null +++ b/tests/base/test_lp_sugar.py @@ -0,0 +1,260 @@ +# SPDX-License-Identifier: BUSL-1.1 +import os +import pytest +from collections import namedtuple + +from web3.constants import ADDRESS_ZERO + + +@pytest.fixture +def sugar_contract(LpSugar, accounts): + # Since we depend on the rest of the protocol, + # we just point to an existing deployment + yield LpSugar.at(os.getenv('LP_SUGAR_ADDRESS_8453')) + + +@pytest.fixture +def TokenStruct(sugar_contract): + method_output = sugar_contract.tokens.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('TokenStruct', members) + + +@pytest.fixture +def LpStruct(sugar_contract): + method_output = sugar_contract.byIndex.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('LpStruct', members) + + +@pytest.fixture +def SwapLpStruct(sugar_contract): + method_output = sugar_contract.forSwaps.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('SwapLpStruct', members) + + +@pytest.fixture +def PositionStruct(sugar_contract): + method_output = sugar_contract.positionsByFactory.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('PositionStruct', members) + + +@pytest.fixture +def LpEpochStruct(sugar_contract): + method_output = sugar_contract.epochsByAddress.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('LpEpochStruct', members) + + +@pytest.fixture +def LpEpochBribeStruct(sugar_contract): + lp_epoch_comp = sugar_contract.epochsByAddress.abi['outputs'][0] + pe_bribe_comp = lp_epoch_comp['components'][4] + members = list(map(lambda _e: _e['name'], pe_bribe_comp['components'])) + + yield namedtuple('LpEpochBribeStruct', members) + + +def test_initial_state(sugar_contract): + assert sugar_contract.voter() == os.getenv('VOTER_8453') + assert sugar_contract.registry() == os.getenv('REGISTRY_8453') + + +def test_byIndex(sugar_contract, LpStruct): + lp = LpStruct(*sugar_contract.byIndex(0)) + + assert lp is not None + assert len(lp) == 27 + assert lp.lp is not None + assert lp.gauge != ADDRESS_ZERO + + +def test_forSwaps(sugar_contract, SwapLpStruct, LpStruct): + first_lp = LpStruct(*sugar_contract.byIndex(0)) + second_lp = LpStruct(*sugar_contract.byIndex(1)) + swap_lps = list(map( + lambda _p: SwapLpStruct(*_p), + sugar_contract.forSwaps(10, 1) + )) + + assert swap_lps is not None + assert len(swap_lps) > 1 + + lp1, lp2 = swap_lps[0:2] + + assert lp1.lp == first_lp.lp + + assert lp2.lp == second_lp.lp + + +def test_tokens(sugar_contract, TokenStruct, LpStruct): + first_lp = LpStruct(*sugar_contract.byIndex(0)) + second_lp = LpStruct(*sugar_contract.byIndex(1)) + tokens = list(map( + lambda _p: TokenStruct(*_p), + sugar_contract.tokens(10, 0, ADDRESS_ZERO, []) + )) + + assert tokens is not None + assert len(tokens) > 1 + + token0, token1, token2 = tokens[0: 3] + + assert token0.token_address == first_lp.token0 + assert token0.symbol is not None + assert token0.decimals > 0 + + assert token1.token_address == first_lp.token1 + assert token2.token_address == second_lp.token0 + + +def test_all(sugar_contract, LpStruct): + first_lp = LpStruct(*sugar_contract.byIndex(0)) + second_lp = LpStruct(*sugar_contract.byIndex(1)) + lps = list(map( + lambda _p: LpStruct(*_p), + sugar_contract.all(10, 0) + )) + + assert lps is not None + assert len(lps) > 1 + + lp1, lp2 = lps[0:2] + + assert lp1.lp == first_lp.lp + assert lp1.gauge == first_lp.gauge + + assert lp2.lp == second_lp.lp + assert lp2.gauge == second_lp.gauge + + +def test_all_pagination(sugar_contract, LpStruct): + max_lps = sugar_contract.MAX_LPS() + + for i in range(0, max_lps, max_lps): + lps = sugar_contract.all(max_lps, 0) + + assert lps is not None + assert len(lps) > max_lps - 1 + + +def test_all_limit_offset(sugar_contract, LpStruct): + second_lp = LpStruct(*sugar_contract.byIndex(1)) + lps = list(map( + lambda _p: LpStruct(*_p), + sugar_contract.all(1, 1) + )) + + assert lps is not None + assert len(lps) == 1 + + lp1 = lps[0] + + assert lp1.lp == second_lp.lp + assert lp1.lp == second_lp.lp + + +def test_positionsByFactory(sugar_contract, PositionStruct): + limit = 100 + offset = 0 + account = os.getenv('TEST_ADDRESS_8453') + factory = os.getenv('TEST_FACTORY_ADDRESS_8453') + + positions = list(map( + lambda _p: PositionStruct(*_p), + sugar_contract.positionsByFactory(limit, offset, account, factory) + )) + + assert positions is not None + assert len(positions) > 0 + + pos = positions[0] + + assert pos.id is not None + assert pos.lp is not None + + +def test_positions_ALM(sugar_contract, PositionStruct): + account = os.getenv('TEST_ALM_ADDRESS_8453') + + positions = list(map( + lambda _p: PositionStruct(*_p), + sugar_contract.positions(1000, 0, account) + )) + + assert positions is not None + assert len(positions) > 0 + + pos = positions[0] + + assert pos.id is not None + assert pos.lp is not None + assert pos.alm is not None + + +def test_epochsByAddress_limit_offset( + sugar_contract, + LpStruct, + LpEpochStruct, + LpEpochBribeStruct + ): + first_lp = LpStruct(*sugar_contract.byIndex(0)) + lp_epochs = list(map( + lambda _p: LpEpochStruct(*_p), + sugar_contract.epochsByAddress(20, 3, first_lp.lp) + )) + + assert lp_epochs is not None + assert len(lp_epochs) > 10 + + epoch = lp_epochs[1] + epoch_bribes = list(map( + lambda _b: LpEpochBribeStruct(*_b), + epoch.bribes + )) + epoch_fees = list(map( + lambda _f: LpEpochBribeStruct(*_f), + epoch.fees + )) + + assert epoch.lp == first_lp.lp + assert epoch.votes > 0 + assert epoch.emissions > 0 + + if len(epoch_bribes) > 0: + assert epoch_bribes[0].amount > 0 + + if len(epoch_fees) > 0: + assert epoch_fees[0].amount > 0 + + +def test_epochsLatest_limit_offset( + sugar_contract, + LpStruct, + LpEpochStruct + ): + second_lp = LpStruct(*sugar_contract.byIndex(1)) + lp_epoch = list(map( + lambda _p: LpEpochStruct(*_p), + sugar_contract.epochsByAddress(1, 0, second_lp.lp) + )) + latest_epoch = list(map( + lambda _p: LpEpochStruct(*_p), + sugar_contract.epochsLatest(1, 1) + )) + + assert lp_epoch is not None + assert len(latest_epoch) == 1 + + pepoch = LpEpochStruct(*lp_epoch[0]) + lepoch = LpEpochStruct(*latest_epoch[0]) + + assert lepoch.lp == pepoch.lp + assert lepoch.ts == pepoch.ts diff --git a/tests/base/test_relay_sugar.py b/tests/base/test_relay_sugar.py new file mode 100644 index 0000000..7a58f36 --- /dev/null +++ b/tests/base/test_relay_sugar.py @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: BUSL-1.1 +import os +import pytest + +from collections import namedtuple +from web3.constants import ADDRESS_ZERO + + +@pytest.fixture +def sugar_contract(RelaySugar, accounts): + # Since we depend on the rest of the protocol, + # we just point to an existing deployment + yield RelaySugar.at(os.getenv('RELAY_SUGAR_ADDRESS_8453')) + + +@pytest.fixture +def RelayStruct(sugar_contract): + method_output = sugar_contract.all.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('RelayStruct', members) + + +def test_initial_state(sugar_contract): + assert sugar_contract.voter() == os.getenv('VOTER_8453') + assert sugar_contract.registries(0) == \ + os.getenv('RELAY_REGISTRY_ADDRESSES_8453').split(',')[0] + assert sugar_contract.ve() is not None + assert sugar_contract.token() is not None + + +def test_all(sugar_contract, RelayStruct): + relays = list(map( + lambda _r: RelayStruct(*_r), + sugar_contract.all(ADDRESS_ZERO) + )) + + assert len(relays) > 5 diff --git a/tests/test_ve_sugar.py b/tests/base/test_ve_sugar.py similarity index 93% rename from tests/test_ve_sugar.py rename to tests/base/test_ve_sugar.py index 7a06c38..071fdc9 100644 --- a/tests/test_ve_sugar.py +++ b/tests/base/test_ve_sugar.py @@ -9,7 +9,7 @@ def sugar_contract(VeSugar, accounts): # Since we depend on the rest of the protocol, # we just point to an existing deployment - yield VeSugar.at(os.getenv('VE_SUGAR_ADDRESS')) + yield VeSugar.at(os.getenv('VE_SUGAR_ADDRESS_8453')) @pytest.fixture @@ -21,9 +21,9 @@ def VeNFTStruct(sugar_contract): def test_initial_state(sugar_contract): - assert sugar_contract.voter() == os.getenv('VOTER_ADDRESS') + assert sugar_contract.voter() == os.getenv('VOTER_8453')) assert sugar_contract.dist() == \ - os.getenv('DIST_ADDRESS') + os.getenv('DIST_8453') assert sugar_contract.ve() is not None diff --git a/tests/test_lp_sugar.py b/tests/optimism/test_lp_sugar.py similarity index 95% rename from tests/test_lp_sugar.py rename to tests/optimism/test_lp_sugar.py index 713f14c..b3f97a0 100644 --- a/tests/test_lp_sugar.py +++ b/tests/optimism/test_lp_sugar.py @@ -10,7 +10,7 @@ def sugar_contract(LpSugar, accounts): # Since we depend on the rest of the protocol, # we just point to an existing deployment - yield LpSugar.at(os.getenv('LP_SUGAR_ADDRESS')) + yield LpSugar.at(os.getenv('LP_SUGAR_ADDRESS_10')) @pytest.fixture @@ -63,8 +63,8 @@ def LpEpochBribeStruct(sugar_contract): def test_initial_state(sugar_contract): - assert sugar_contract.voter() == os.getenv('VOTER_ADDRESS') - assert sugar_contract.registry() == os.getenv('REGISTRY_ADDRESS') + assert sugar_contract.voter() == os.getenv('VOTER_10') + assert sugar_contract.registry() == os.getenv('REGISTRY_10') def test_byIndex(sugar_contract, LpStruct): @@ -164,8 +164,8 @@ def test_all_limit_offset(sugar_contract, LpStruct): def test_positionsByFactory(sugar_contract, PositionStruct): limit = 100 offset = 0 - account = os.getenv('TEST_ADDRESS') - factory = os.getenv('TEST_FACTORY_ADDRESS') + account = os.getenv('TEST_ADDRESS_10') + factory = os.getenv('TEST_FACTORY_ADDRESS_10') positions = list(map( lambda _p: PositionStruct(*_p), @@ -182,7 +182,7 @@ def test_positionsByFactory(sugar_contract, PositionStruct): def test_positions_ALM(sugar_contract, PositionStruct): - account = os.getenv('TEST_ALM_ADDRESS') + account = os.getenv('TEST_ALM_ADDRESS_10') positions = list(map( lambda _p: PositionStruct(*_p), diff --git a/tests/test_relay_sugar.py b/tests/optimism/test_relay_sugar.py similarity index 88% rename from tests/test_relay_sugar.py rename to tests/optimism/test_relay_sugar.py index 459ca83..7620582 100644 --- a/tests/test_relay_sugar.py +++ b/tests/optimism/test_relay_sugar.py @@ -10,7 +10,7 @@ def sugar_contract(RelaySugar, accounts): # Since we depend on the rest of the protocol, # we just point to an existing deployment - yield RelaySugar.at(os.getenv('RELAY_SUGAR_ADDRESS')) + yield RelaySugar.at(os.getenv('RELAY_SUGAR_ADDRESS_10')) @pytest.fixture @@ -22,7 +22,7 @@ def RelayStruct(sugar_contract): def test_initial_state(sugar_contract): - assert sugar_contract.voter() == os.getenv('VOTER_ADDRESS') + assert sugar_contract.voter() == os.getenv('VOTER_10') assert sugar_contract.registries(0) == \ os.getenv('RELAY_REGISTRY_ADDRESSES').split(',')[0] assert sugar_contract.ve() is not None diff --git a/tests/optimism/test_ve_sugar.py b/tests/optimism/test_ve_sugar.py new file mode 100644 index 0000000..28b9cfc --- /dev/null +++ b/tests/optimism/test_ve_sugar.py @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: BUSL-1.1 +import os +import pytest + +from collections import namedtuple + + +@pytest.fixture +def sugar_contract(VeSugar, accounts): + # Since we depend on the rest of the protocol, + # we just point to an existing deployment + yield VeSugar.at(os.getenv('VE_SUGAR_ADDRESS_10')) + + +@pytest.fixture +def VeNFTStruct(sugar_contract): + method_output = sugar_contract.byId.abi['outputs'][0] + members = list(map(lambda _e: _e['name'], method_output['components'])) + + yield namedtuple('VeNFTStruct', members) + + +def test_initial_state(sugar_contract): + assert sugar_contract.voter() == os.getenv('VOTER_10') + assert sugar_contract.dist() == \ + os.getenv('DIST_10') + assert sugar_contract.ve() is not None + + +def test_byId(sugar_contract, VeNFTStruct): + venft = VeNFTStruct(*sugar_contract.byId(1)) + + assert venft is not None + assert len(venft) == 14 + assert venft.id is not None + assert len(venft.votes) > 0 + assert venft.voted_at > 0 + + +def test_byAccount(sugar_contract, VeNFTStruct): + venft = VeNFTStruct(*sugar_contract.byId(1)) + acc_venft = list(map( + lambda _v: VeNFTStruct(*_v), + sugar_contract.byAccount(venft.account) + )) + + assert venft is not None + assert len(venft) == 14 + assert venft.account == acc_venft[0].account + + +def test_all(sugar_contract, VeNFTStruct): + first_venft = VeNFTStruct(*sugar_contract.byId(1)) + second_venft = VeNFTStruct(*sugar_contract.byId(2)) + venfts = list(map( + lambda _v: VeNFTStruct(*_v), + sugar_contract.all(30, 0) + )) + + assert venfts is not None + assert len(venfts) > 2 + + venft1, venft2 = venfts[0:2] + + assert venft1.id == first_venft.id + assert venft1.account == first_venft.account + + assert venft2.id == second_venft.id + assert venft2.account == second_venft.account + + +def test_all_limit_offset(sugar_contract, VeNFTStruct): + second_venft = VeNFTStruct(*sugar_contract.byId(1)) + venfts = list(map( + lambda _v: VeNFTStruct(*_v), + sugar_contract.all(1, 1) + )) + + assert venfts is not None + assert len(venfts) == 1 + + venft1 = venfts[0] + + assert venft1.id == second_venft.id + assert venft1.account == second_venft.account