Skip to content

Commit

Permalink
Update proto files, fix memo in transfer.
Browse files Browse the repository at this point in the history
  • Loading branch information
dowlandaiello committed Jul 27, 2024
1 parent 8327d96 commit 5cbae39
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 32 deletions.
1 change: 1 addition & 0 deletions local-interchaintest/tests/transfer_osmosis.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async def main() -> None:
"osmo1hj5fveer5cjtn4wd6wstzugjfdxzl0xpwhpz63",
ctx,
1,
memo="hi",
)

balance_after_resp = try_multiple_clients(
Expand Down
30 changes: 20 additions & 10 deletions proto/ibc/applications/transfer/v1/transfer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,9 @@ syntax = "proto3";

package ibc.applications.transfer.v1;

option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types";
import "gogoproto/gogo.proto";

// DenomTrace contains the base denomination for ICS20 fungible tokens and the
// source tracing information path.
message DenomTrace {
// path defines the chain of port/channel identifiers used for tracing the
// source of the fungible token.
string path = 1;
// base denomination of the relayed fungible token.
string base_denom = 2;
}
option go_package = "github.com/cosmos/ibc-go/v9/modules/apps/transfer/types";

// Params defines the set of IBC transfer parameters.
// NOTE: To prevent a single token from being transferred, set the
Expand All @@ -26,3 +18,21 @@ message Params {
// chain.
bool receive_enabled = 2;
}

// Forwarding defines a list of port ID, channel ID pairs determining the path
// through which a packet must be forwarded, and an unwind boolean indicating if
// the coin should be unwinded to its native chain before forwarding.
message Forwarding {
// optional unwinding for the token transfered
bool unwind = 1;
// optional intermediate path through which packet will be forwarded
repeated Hop hops = 2 [(gogoproto.nullable) = false];
}

// Hop defines a port ID, channel ID pair specifying where tokens must be forwarded
// next in a multihop transfer.
message Hop {
option (gogoproto.goproto_stringer) = false;
string port_id = 1;
string channel_id = 2;
}
12 changes: 8 additions & 4 deletions proto/ibc/applications/transfer/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ syntax = "proto3";

package ibc.applications.transfer.v1;

option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types";
option go_package = "github.com/cosmos/ibc-go/v9/modules/apps/transfer/types";

import "amino/amino.proto";
import "gogoproto/gogo.proto";
Expand Down Expand Up @@ -35,8 +35,8 @@ message MsgTransfer {
string source_port = 1;
// the channel by which the packet will be sent
string source_channel = 2;
// the tokens to be transferred
cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
// the token to be transferred. this field has been replaced by the tokens field.
cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, deprecated = true];
// the sender address
string sender = 4;
// the recipient address on the destination chain
Expand All @@ -49,6 +49,10 @@ message MsgTransfer {
uint64 timeout_timestamp = 7;
// optional memo
string memo = 8;
// tokens to be transferred
repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false];
// optional forwarding information
Forwarding forwarding = 10;
}

// MsgTransferResponse defines the Msg/Transfer response type.
Expand Down Expand Up @@ -76,4 +80,4 @@ message MsgUpdateParams {

// MsgUpdateParamsResponse defines the response structure for executing a
// MsgUpdateParams message.
message MsgUpdateParamsResponse {}
message MsgUpdateParamsResponse {}
24 changes: 7 additions & 17 deletions src/strategies/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,23 +939,12 @@ async def transfer_raw(
"""

# Create a messate transfering the funds
msg = (
tx_pb2.MsgTransfer( # pylint: disable=no-member
source_port="transfer",
source_channel=src_channel_id,
sender=sender_addr,
receiver=receiver_addr,
timeout_timestamp=time.time_ns() + 600 * 10**9,
memo=memo,
)
if memo
else tx_pb2.MsgTransfer( # pylint: disable=no-member
source_port="transfer",
source_channel=src_channel_id,
sender=sender_addr,
receiver=receiver_addr,
timeout_timestamp=time.time_ns() + 600 * 10**9,
)
msg = tx_pb2.MsgTransfer( # pylint: disable=no-member
source_port="transfer",
source_channel=src_channel_id,
sender=sender_addr,
receiver=receiver_addr,
timeout_timestamp=time.time_ns() + 600 * 10**9,
)

msg.token.CopyFrom(
Expand All @@ -975,6 +964,7 @@ async def transfer_raw(
SigningCfg.direct(ctx.wallet.public_key(), acc.sequence),
f"100000{src_chain_fee_denom}",
1000000,
memo=memo,
)
tx.sign(ctx.wallet.signer(), src_chain_id, acc.number)
tx.complete()
Expand Down
108 changes: 107 additions & 1 deletion tests/test_strategy_util.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# type: ignore

import json
from typing import Any
from src.scheduler import Ctx
from src.contracts.route import Leg
from src.strategies.util import collapse_route, build_atomic_arb
from src.strategies.util import collapse_route, build_atomic_arb, transfer_raw
from src.util import denom_info_on_chain, denom_route, custom_neutron_network_config
from tests.test_scheduler import TEST_WALLET_MNEMONIC
from cosmpy.aerial.wallet import LocalWallet
from cosmpy.aerial.client import LedgerClient
from cosmpy.crypto.address import Address
import pytest
import aiohttp

pytest_plugins = ("pytest_asyncio",)

Expand Down Expand Up @@ -98,3 +105,102 @@ def test_build_atomic_arb() -> None:
collapsed_atomic[0],
LocalWallet.from_mnemonic(TEST_WALLET_MNEMONIC, prefix="neutron"),
)


@pytest.mark.asyncio
async def test_transfer_raw() -> None:
"""
Transfers a tiny amount of USDC to osmosis.
"""

net_config = None

with open("net_conf.json", "r", encoding="utf-8") as nf:
net_config = json.load(nf)

wallet = LocalWallet.from_mnemonic(TEST_WALLET_MNEMONIC, prefix="neutron")

async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(force_close=True, limit_per_host=1),
timeout=aiohttp.ClientTimeout(total=30),
) as session:
ctx: Ctx[Any] = Ctx(
{
chain_id: [
LedgerClient(
custom_neutron_network_config(endpoint, chain_id=chain_id)
)
for endpoint in endpoints["grpc"]
]
for chain_id, endpoints in net_config.items()
},
net_config,
wallet,
{},
None,
False,
session,
[],
{},
{},
)

denom_infos_on_dest = await denom_info_on_chain(
"neutron-1",
"ibc/B559A80D62249C8AA07A380E2A2BEA6E5CA9A6F079C912C3A9E9B494105E4F81",
"osmosis-1",
session,
)

if not denom_infos_on_dest:
raise ValueError(
f"Missing denom info for transfer {denom} (neutron-1) -> osmosis-1"
)

ibc_route = await denom_route(
"neutron-1",
"ibc/B559A80D62249C8AA07A380E2A2BEA6E5CA9A6F079C912C3A9E9B494105E4F81",
"osmosis-1",
denom_infos_on_dest[0].denom,
session,
)

if not ibc_route or len(ibc_route) == 0:
raise ValueError(f"No route from {denom} to {leg.backend.chain_id}")

src_channel_id = ibc_route[0].channel
sender_addr = str(
Address(wallet.public_key(), prefix=ibc_route[0].from_chain.bech32_prefix)
)
receiver_addr = str(
Address(wallet.public_key(), prefix=ibc_route[0].to_chain.bech32_prefix)
)

memo: Optional[str] = None

for ibc_leg in reversed(ibc_route[1:]):
memo = json.dumps(
{
"forward": {
"receiver": "pfm",
"port": ibc_leg.port,
"channel": ibc_leg.channel,
"timeout": "10m",
"retries": 2,
"next": memo,
}
}
)

await transfer_raw(
"ibc/B559A80D62249C8AA07A380E2A2BEA6E5CA9A6F079C912C3A9E9B494105E4F81",
ibc_route[0].from_chain.chain_id,
"untrn",
src_channel_id,
ibc_route[0].to_chain.chain_id,
sender_addr,
receiver_addr,
ctx,
1,
memo=memo,
)

0 comments on commit 5cbae39

Please sign in to comment.