Skip to content

Commit

Permalink
Ack & timeout relay msgs
Browse files Browse the repository at this point in the history
  • Loading branch information
grod220 committed Sep 25, 2024
1 parent 2381922 commit 4dc1cdf
Showing 1 changed file with 178 additions and 68 deletions.
246 changes: 178 additions & 68 deletions packages/ui/components/ui/tx/actions-views/ibc-relay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,93 +4,119 @@ import {
FungibleTokenPacketData,
IbcRelay,
} from '@penumbra-zone/protobuf/penumbra/core/component/ibc/v1/ibc_pb';
import { MsgRecvPacket } from '@penumbra-zone/protobuf/ibc/core/channel/v1/tx_pb';
import {
MsgAcknowledgement,
MsgRecvPacket,
MsgTimeout,
MsgTimeoutOnClose,
} from '@penumbra-zone/protobuf/ibc/core/channel/v1/tx_pb';
import { MsgUpdateClient } from '@penumbra-zone/protobuf/ibc/core/client/v1/tx_pb';
import { UnimplementedView } from './unimplemented-view.tsx';
import { uint8ArrayToBase64 } from '@penumbra-zone/types/base64';
import { ReactElement } from 'react';
import { Packet } from '@penumbra-zone/protobuf/ibc/core/channel/v1/channel_pb';
import { getUtcTime } from './isc20-withdrawal.tsx';
import { useMemo } from 'react';

// Packet data stored as json string encoded into bytes
const parsePacket = ({ packet }: MsgRecvPacket): FungibleTokenPacketData | undefined => {
if (!packet?.data) {
// Attempt to parse data w/ fallbacks if unknown or failures
const ParsedPacketData = ({
data,
dataParser,
}: {
data: Uint8Array;
dataParser?: (arg: Uint8Array) => ReactElement;
}) => {
if (!data.length) {
return undefined;
}

if (!dataParser) {
return <ActionDetails.Row label='Data'>Unknown packet data</ActionDetails.Row>;
}

try {
const dataString = new TextDecoder().decode(packet.data);
return FungibleTokenPacketData.fromJsonString(dataString);
return dataParser(data);
} catch (e) {
return undefined;
return <ActionDetails.Row label='Data'>Error while parsing data</ActionDetails.Row>;
}
};

const MsgResvComponent = ({ packet }: { packet: MsgRecvPacket }) => {
const packetData = useMemo(() => parsePacket(packet), [packet]);
const PacketRows = ({
packet,
dataParser,
}: {
packet: Packet;
dataParser?: (arg: Uint8Array) => ReactElement;
}) => {
return (
<>
<ParsedPacketData data={packet.data} dataParser={dataParser} />
{!!packet.sequence && (
<ActionDetails.Row label='Sequence'>{Number(packet.sequence)}</ActionDetails.Row>
)}
{!!packet.sourcePort && (
<ActionDetails.Row label='Source Port'>{packet.sourcePort}</ActionDetails.Row>
)}
{!!packet.sourceChannel && (
<ActionDetails.Row label='Source Channel'>{packet.sourceChannel}</ActionDetails.Row>
)}
{!!packet.destinationPort && (
<ActionDetails.Row label='Destination Port'>{packet.destinationPort}</ActionDetails.Row>
)}
{!!packet.destinationChannel && (
<ActionDetails.Row label='Destination Channel'>
{packet.destinationChannel}
</ActionDetails.Row>
)}
{!!packet.timeoutHeight?.revisionHeight && (
<ActionDetails.Row label='Timeout revision height'>
{Number(packet.timeoutHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!packet.timeoutHeight?.revisionNumber && (
<ActionDetails.Row label='Timeout revision number'>
{Number(packet.timeoutHeight.revisionNumber)}
</ActionDetails.Row>
)}
{!!packet.timeoutTimestamp && (
<ActionDetails.Row label='Timeout timestamp'>
{getUtcTime(packet.timeoutTimestamp)}
</ActionDetails.Row>
)}
</>
);
};

// Packet data stored as json string encoded into bytes
const parseRecvPacket = (packetData: Uint8Array) => {
const dataString = new TextDecoder().decode(packetData);
const parsed = FungibleTokenPacketData.fromJsonString(dataString);
return (
<>
{!!parsed.sender && (
<ActionDetails.Row label='Sender'>
<ActionDetails.TruncatedText>{parsed.sender}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!parsed.receiver && (
<ActionDetails.Row label='Receiver'>
<ActionDetails.TruncatedText>{parsed.receiver}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!parsed.denom && <ActionDetails.Row label='Denom'>{parsed.denom}</ActionDetails.Row>}
{!!parsed.amount && <ActionDetails.Row label='Amount'>{parsed.amount}</ActionDetails.Row>}
{'memo' in parsed && <ActionDetails.Row label='Memo'>{parsed.memo}</ActionDetails.Row>}
</>
);
};

const MsgResvComponent = ({ packet }: { packet: MsgRecvPacket }) => {
return (
<ViewBox
label='IBC Relay: Msg Received'
visibleContent={
<ActionDetails>
{packetData === undefined && (
<ActionDetails.Row label='Data'>Unknown packet data</ActionDetails.Row>
)}
{!!packetData?.sender && (
<ActionDetails.Row label='Sender'>
<ActionDetails.TruncatedText>{packetData.sender}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!packetData?.receiver && (
<ActionDetails.Row label='Receiver'>
<ActionDetails.TruncatedText>{packetData.receiver}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!packetData?.denom && (
<ActionDetails.Row label='Denom'>{packetData.denom}</ActionDetails.Row>
)}
{!!packetData?.amount && (
<ActionDetails.Row label='Amount'>{packetData.amount}</ActionDetails.Row>
)}
{packetData && 'memo' in packetData && (
<ActionDetails.Row label='Memo'>{packetData.memo}</ActionDetails.Row>
)}
{!!packet.packet?.sequence && (
<ActionDetails.Row label='Sequence'>{Number(packet.packet.sequence)}</ActionDetails.Row>
)}
{!!packet.packet?.sourcePort && (
<ActionDetails.Row label='Source Port'>{packet.packet.sourcePort}</ActionDetails.Row>
)}
{!!packet.packet?.sourceChannel && (
<ActionDetails.Row label='Source Channel'>
{packet.packet.sourceChannel}
</ActionDetails.Row>
)}
{!!packet.packet?.destinationPort && (
<ActionDetails.Row label='Destination Port'>
{packet.packet.destinationPort}
</ActionDetails.Row>
)}
{!!packet.packet?.destinationChannel && (
<ActionDetails.Row label='Destination Channel'>
{packet.packet.destinationChannel}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutHeight?.revisionHeight && (
<ActionDetails.Row label='Timeout revision height'>
{Number(packet.packet.timeoutHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutHeight?.revisionNumber && (
<ActionDetails.Row label='Timeout revision number'>
{Number(packet.packet.timeoutHeight.revisionNumber)}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutTimestamp && (
<ActionDetails.Row label='Timeout timestamp'>
{getUtcTime(packet.packet.timeoutTimestamp)}
</ActionDetails.Row>
)}
{!!packet.packet && <PacketRows packet={packet.packet} dataParser={parseRecvPacket} />}

<ActionDetails.Row label='Signer'>{packet.signer}</ActionDetails.Row>
{!!packet.proofHeight?.revisionHeight && (
<ActionDetails.Row label='Proof revision height'>
Expand Down Expand Up @@ -127,6 +153,72 @@ const UpdateClientComponent = ({ update }: { update: MsgUpdateClient }) => {
);
};

const MsgTimeoutComponent = ({ timeout }: { timeout: MsgTimeout }) => {
return (
<ViewBox
label='IBC Relay: Msg Timeout'
visibleContent={
<ActionDetails>
{!!timeout.packet && <PacketRows packet={timeout.packet} />}
{!!timeout.proofHeight?.revisionHeight && (
<ActionDetails.Row label='Proof revision height'>
{Number(timeout.proofHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!timeout.proofHeight?.revisionNumber && (
<ActionDetails.Row label='Proof revision number'>
{Number(timeout.proofHeight.revisionNumber)}
</ActionDetails.Row>
)}
<ActionDetails.Row label='Next Sequence Received'>
{Number(timeout.nextSequenceRecv)}
</ActionDetails.Row>
<ActionDetails.Row label='Signer'>{timeout.signer}</ActionDetails.Row>
<ActionDetails.Row label='Proof unreceived'>
<ActionDetails.TruncatedText>
{uint8ArrayToBase64(timeout.proofUnreceived)}
</ActionDetails.TruncatedText>
</ActionDetails.Row>
</ActionDetails>
}
/>
);
};

const MsgAckComponent = ({ ack }: { ack: MsgAcknowledgement }) => {
return (
<ViewBox
label='IBC Relay: Msg Acknowledgement'
visibleContent={
<ActionDetails>
{!!ack.packet && <PacketRows packet={ack.packet} />}
{!!ack.proofHeight?.revisionHeight && (
<ActionDetails.Row label='Proof revision height'>
{Number(ack.proofHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!ack.proofHeight?.revisionNumber && (
<ActionDetails.Row label='Proof revision number'>
{Number(ack.proofHeight.revisionNumber)}
</ActionDetails.Row>
)}
<ActionDetails.Row label='Signer'>{ack.signer}</ActionDetails.Row>
<ActionDetails.Row label='Ackknowledgement'>
<ActionDetails.TruncatedText>
{uint8ArrayToBase64(ack.acknowledgement)}
</ActionDetails.TruncatedText>
</ActionDetails.Row>
<ActionDetails.Row label='Proof Acked'>
<ActionDetails.TruncatedText>
{uint8ArrayToBase64(ack.proofAcked)}
</ActionDetails.TruncatedText>
</ActionDetails.Row>
</ActionDetails>
}
/>
);
};

export const IbcRelayComponent = ({ value }: { value: IbcRelay }) => {
if (value.rawAction?.is(MsgRecvPacket.typeName)) {
const packet = new MsgRecvPacket();
Expand All @@ -140,5 +232,23 @@ export const IbcRelayComponent = ({ value }: { value: IbcRelay }) => {
return <UpdateClientComponent update={update} />;
}

if (value.rawAction?.is(MsgTimeout.typeName)) {
const timeout = new MsgTimeout();
value.rawAction.unpackTo(timeout);
return <MsgTimeoutComponent timeout={timeout} />;
}

if (value.rawAction?.is(MsgTimeoutOnClose.typeName)) {
const timeout = new MsgTimeoutOnClose();
value.rawAction.unpackTo(timeout);
return <MsgTimeoutComponent timeout={timeout} />;
}

if (value.rawAction?.is(MsgAcknowledgement.typeName)) {
const ack = new MsgAcknowledgement();
value.rawAction.unpackTo(ack);
return <MsgAckComponent ack={ack} />;
}

return <UnimplementedView label='IBC Relay' />;
};

0 comments on commit 4dc1cdf

Please sign in to comment.