Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions gno.land/r/aib/ibc/apps/transfer/app.gno
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ func (a *App) OnSendPacket(
// data, then we can remove this restriction.
// Non-IBC GRC20 tokens use aliases (slashes replaced with colons)
// so they pass this check naturally.
if strings.Contains(token.Denom.Base, "/") {
return ufmt.Errorf("base denomination %s cannot contain slashes for IBC v2 packet", token.Denom.Base)
if err := validateBaseDenomNoSlash(token); err != nil {
return err
}

coin, err := token.ToCoin()
Expand Down Expand Up @@ -224,6 +224,10 @@ func (a *App) OnRecvPacket(
ack = types.NewErrorAppAcknowledgement(ackErr)
return types.RecvPacketResult{Status: types.PacketStatus_Failure}
}
if ackErr = validateBaseDenomNoSlash(token); ackErr != nil {
ack = types.NewErrorAppAcknowledgement(ackErr)
return types.RecvPacketResult{Status: types.PacketStatus_Failure}
}
// This is the prefix that would have been prefixed to the denomination
// on sender chain IF and only if the token originally came from the
// receiving chain.
Expand Down Expand Up @@ -291,6 +295,16 @@ func (a *App) OnRecvPacket(
return recvResult
}

// validateBaseDenomNoSlash rejects base denominations containing a slash.
// IBC v2 packets do not carry channel identifiers, so denomination traces
// cannot be unambiguously separated from a slashed base denomination.
func validateBaseDenomNoSlash(token Token) error {
if strings.Contains(token.Denom.Base, "/") {
return ufmt.Errorf("base denomination %s cannot contain slashes for IBC v2 packet", token.Denom.Base)
}
return nil
}

// OnAcknowledgementPacket responds to the success or failure of a packet
// acknowledgment written on the receiving chain.
//
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// PKGPATH: gno.land/r/aib/main
Comment thread
tbruyelle marked this conversation as resolved.
package main

import (
"testing"
"time"

tmtesting "gno.land/p/aib/ibc/lightclient/tendermint/testing"
"gno.land/p/aib/ibc/types"

"gno.land/r/aib/ibc/apps/transfer"
"gno.land/r/aib/ibc/core"
)

func main(cur realm) {
var (
chainID = "chain-id-2"
clientState = tmtesting.NewClientState(chainID, types.NewHeight(2, 2))
apphash = tmtesting.Hash("apphash")
trustedValset = tmtesting.GenValset()
consensusState = tmtesting.GenConsensusState(time.Now(), apphash, trustedValset.Hash())
)
clientID := core.CreateClient(cross(cur), clientState, consensusState)
core.RegisterCounterparty(cross(cur), clientID, [][]byte{[]byte("iavlStoreKey"), []byte("prefix2")}, "07-tendermint-2")

signer := cur.Previous().Address()
payload := transfer.NewFungibleTokenPacketData("factory/alice/token", "100", signer.String(), "atone1user", "")
packet := types.MsgSendPacket{
SourceClient: clientID,
TimeoutTimestamp: uint64(time.Now().Add(time.Hour).Unix()),
Payloads: []types.Payload{
{
SourcePort: transfer.PortID,
DestinationPort: transfer.PortID,
Encoding: transfer.EncodingProtobuf,
Value: payload.ProtoMarshal(),
Version: transfer.V1,
},
},
}
testing.SetOriginCaller(signer)

core.SendPacket(cross(cur), packet)
}

// Error:
// send packet failed for payload #0 app "transfer": base denomination factory/alice/token cannot contain slashes for IBC v2 packet
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
// PKGPATH: gno.land/r/aib/main
package main

import (
"encoding/base64"
"encoding/hex"
"time"

tmtesting "gno.land/p/aib/ibc/lightclient/tendermint/testing"
"gno.land/p/aib/ibc/types"
"gno.land/p/aib/ics23"
"gno.land/p/nt/testutils/v0"
"gno.land/r/aib/ibc/apps/transfer"
"gno.land/r/aib/ibc/core"
)

func main(cur realm) {
var (
chainID = "chain-id-2"
trustedHeight = types.NewHeight(2, 2)
clientState = tmtesting.NewClientState(chainID, trustedHeight)
// NOTE this apphash was provided by the gen-proof command below.
apphash, _ = hex.DecodeString("6080c593423ad30569d57d29a92e1068fc2fae7e5e84d98bbf0ad30dc484b48a")
trustedValset = tmtesting.GenValset()
consensusState = tmtesting.GenConsensusState(time.Now(), apphash, trustedValset.Hash())
counterpartyID = "07-tendermint-42"
)
clientID := core.CreateClient(cross(cur), clientState, consensusState)
core.RegisterCounterparty(cross(cur), clientID, [][]byte{[]byte("iavlStoreKey"), []byte("prefix2")}, counterpartyID)

// ---- RecvPacket: counterparty is the source, but slashed base is rejected.
receiver := testutils.TestAddress("receiver")
recvPayload := transfer.NewFungibleTokenPacketData(
"factory/alice/token", // base denom containing slashes
"100",
"atone1user",
receiver.String(),
"",
)
recvPayloadBz := recvPayload.ProtoMarshal()
// NOTE this base64 value is used in payload.value in the gen-proof command below.
println("Payload proto:", base64.StdEncoding.EncodeToString(recvPayloadBz))

specs := ics23.IavlSpec()
// NOTE code generated by:
// go run -C ./cmd/gen-proof . 'prefix2' '07-tendermint-42' 'packet' '{"sequence":1,"source_client":"07-tendermint-42","destination_client":"07-tendermint-1","timeout_timestamp":1234571490,"payloads":[{"source_port":"transfer","destination_port":"transfer","encoding":"application/x-protobuf","value":"ChNmYWN0b3J5L2FsaWNlL3Rva2VuEgMxMDAaCmF0b25lMXVzZXIiKGcxd2Zqa3hldGZ3ZWpoeWg2bHRhMDQ3aDZsdGEwNDdoNmxsbTgyeWw=","version":"ics20-1"}]}'
recvProof := []ics23.CommitmentProof{

// iavl proof
ics23.CommitmentProof_Exist{
Exist: &ics23.ExistenceProof{
Key: []byte("\x70\x72\x65\x66\x69\x78\x32\x30\x37\x2d\x74\x65\x6e\x64\x65\x72\x6d\x69\x6e\x74\x2d\x34\x32\x01\x00\x00\x00\x00\x00\x00\x00\x01"),
Value: []byte("\xae\x16\x63\xaf\xf8\xeb\xba\x8f\xd8\x64\xdc\xd0\x08\xeb\xbe\xbf\x26\xb4\xb8\xd9\x48\x3e\x9b\x45\xdb\x66\x45\x36\xb9\xe6\x69\x94"),
Leaf: &ics23.LeafOp{
Hash: specs.LeafSpec.Hash,
PrehashKey: specs.LeafSpec.PrehashKey,
PrehashValue: specs.LeafSpec.PrehashValue,
Length: specs.LeafSpec.Length,
Prefix: []byte("\x00\x02\x02"),
},
Path: []*ics23.InnerOp{
{
Hash: specs.InnerSpec.Hash,
Prefix: []byte("\x02\x04\x02\x20\x35\xf8\xea\x80\x53\x90\xe0\x84\x85\x4f\x39\x9b\x42\xcc\xde\xae\xa3\x3a\x1d\xed\xc1\x15\x63\x8a\xc4\x8d\x06\x00\x63\x7d\xba\x1f\x20"),
Suffix: []byte(""),
},
{
Hash: specs.InnerSpec.Hash,
Prefix: []byte("\x04\x08\x02\x20"),
Suffix: []byte("\x20\x79\x8e\x2c\xaa\x96\xfd\xfb\xa3\x76\xdd\xeb\x47\x99\x99\x54\xd2\xf4\x7e\x65\x16\x22\x64\xb0\x53\x6a\xb5\xdf\xf7\xfc\x0a\x2e\x07"),
},
{
Hash: specs.InnerSpec.Hash,
Prefix: []byte("\x06\x0c\x02\x20\x9a\xf3\x7d\xd5\x95\xa0\x19\x08\x03\xb5\xe0\x5a\xae\xf4\x2a\xe3\xfa\xd4\x99\xe4\xfb\xe3\x7f\x7c\xd3\x1c\xad\xff\x22\xa9\xee\x74\x20"),
Suffix: []byte(""),
},
},
},
},

// rootmulti proof
ics23.CommitmentProof_Exist{
Exist: &ics23.ExistenceProof{
Key: []byte("\x69\x61\x76\x6c\x53\x74\x6f\x72\x65\x4b\x65\x79"),
Value: []byte("\xa0\xe3\x05\xd4\x1d\x1c\x67\x1c\x00\xc7\xe7\x3e\xb9\x69\x8c\x80\x73\xdd\x76\x73\xf4\x35\xcc\x3d\x96\xf5\xb1\x92\x54\x28\x98\x38"),
Leaf: &ics23.LeafOp{
Hash: specs.LeafSpec.Hash,
PrehashKey: specs.LeafSpec.PrehashKey,
PrehashValue: specs.LeafSpec.PrehashValue,
Length: specs.LeafSpec.Length,
Prefix: []byte("\x00"),
},
Path: []*ics23.InnerOp{},
},
},
}

recvPacket := types.MsgRecvPacket{
Packet: types.Packet{
Sequence: 1,
SourceClient: counterpartyID,
DestinationClient: clientID,
TimeoutTimestamp: uint64(time.Now().Add(time.Hour).Unix()),
Payloads: []types.Payload{{
SourcePort: transfer.PortID,
DestinationPort: transfer.PortID,
Encoding: transfer.EncodingProtobuf,
Value: recvPayloadBz,
Version: transfer.V1,
}},
},
ProofCommitment: recvProof,
ProofHeight: trustedHeight,
}
core.RecvPacket(cross(cur), recvPacket)

voucherDenom := transfer.NewDenom(
"factory/alice/token",
transfer.NewHop(transfer.PortID, clientID),
).IBCDenom()
println("voucher balance after recv:", transfer.VoucherBalanceOf(voucherDenom, receiver))
}

// Output:
// Payload proto: ChNmYWN0b3J5L2FsaWNlL3Rva2VuEgMxMDAaCmF0b25lMXVzZXIiKGcxd2Zqa3hldGZ3ZWpoeWg2bHRhMDQ3aDZsdGEwNDdoNmxsbTgyeWw=
// voucher balance after recv: 0

// Events:
// [
// {
// "type": "create_client",
// "attrs": [
// {
// "key": "client_id",
// "value": "07-tendermint-1"
// },
// {
// "key": "client_type",
// "value": "07-tendermint"
// },
// {
// "key": "consensus_heights",
// "value": "2/2"
// }
// ],
// "pkg_path": "gno.land/r/aib/ibc/core"
// },
// {
// "type": "recv_packet",
// "attrs": [
// {
// "key": "packet_source_client",
// "value": "07-tendermint-42"
// },
// {
// "key": "packet_dest_client",
// "value": "07-tendermint-1"
// },
// {
// "key": "packet_sequence",
// "value": "1"
// },
// {
// "key": "packet_timeout_timestamp",
// "value": "1234571490"
// },
// {
// "key": "encoded_packet_hex",
// "value": "0801121030372d74656e6465726d696e742d34321a0f30372d74656e6465726d696e742d3120e2a1d8cc042a87010a087472616e7366657212087472616e736665721a0769637332302d3122166170706c69636174696f6e2f782d70726f746f6275662a500a13666163746f72792f616c6963652f746f6b656e12033130301a0a61746f6e6531757365722228673177666a6b7865746677656a687968366c746130343768366c746130343768366c6c6d3832796c"
// }
// ],
// "pkg_path": "gno.land/r/aib/ibc/core"
// },
// {
// "type": "fungible_token_packet",
// "attrs": [
// {
// "key": "sender",
// "value": "atone1user"
// },
// {
// "key": "receiver",
// "value": "g1wfjkxetfwejhyh6lta047h6lta047h6llm82yl"
// },
// {
// "key": "denom",
// "value": "factory/alice/token"
// },
// {
// "key": "amount",
// "value": "100"
// },
// {
// "key": "memo",
// "value": ""
// },
// {
// "key": "success",
// "value": "false"
// },
// {
// "key": "error",
// "value": "base denomination factory/alice/token cannot contain slashes for IBC v2 packet"
// }
// ],
// "pkg_path": "gno.land/r/aib/ibc/apps/transfer"
// },
// {
// "type": "write_acknowledgement",
// "attrs": [
// {
// "key": "packet_source_client",
// "value": "07-tendermint-42"
// },
// {
// "key": "packet_dest_client",
// "value": "07-tendermint-1"
// },
// {
// "key": "packet_sequence",
// "value": "1"
// },
// {
// "key": "packet_timeout_timestamp",
// "value": "1234571490"
// },
// {
// "key": "encoded_packet_hex",
// "value": "0801121030372d74656e6465726d696e742d34321a0f30372d74656e6465726d696e742d3120e2a1d8cc042a87010a087472616e7366657212087472616e736665721a0769637332302d3122166170706c69636174696f6e2f782d70726f746f6275662a500a13666163746f72792f616c6963652f746f6b656e12033130301a0a61746f6e6531757365722228673177666a6b7865746677656a687968366c746130343768366c746130343768366c6c6d3832796c"
// },
// {
// "key": "encoded_acknowledgement_hex",
// "value": "0a204774d4a575993f963b1c06573736617a457abef8589178db8d10c94b4ab511ab"
// }
// ],
// "pkg_path": "gno.land/r/aib/ibc/core"
// }
// ]
Loading