Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ibc: transparent address support #1950

Merged
merged 20 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { generateTransactionInfo } from '@penumbra-zone/wasm/transaction';
import { TransactionInfo } from '@penumbra-zone/protobuf/penumbra/view/v1/view_pb';
import { fvkCtx } from '../ctx/full-viewing-key.js';
import { txvTranslator } from './util/transaction-view.js';

export const transactionInfoByHash: Impl['transactionInfoByHash'] = async (req, ctx) => {
if (!req.id) {
Expand All @@ -23,11 +24,15 @@
throw new ConnectError('Transaction not available', Code.NotFound);
}

const { txp: perspective, txv: view } = await generateTransactionInfo(
let { txp: perspective, txv: view } = await generateTransactionInfo(

Check failure on line 27 in packages/services/src/view-service/transaction-info-by-hash.ts

View workflow job for this annotation

GitHub Actions / Lint

'perspective' is never reassigned. Use 'const' instead
await fvk(),
transaction,
indexedDb.constants(),
);

// Invoke a higher-level translator on the transaction view.
view = await txvTranslator(view);

const txInfo = new TransactionInfo({ height, id: req.id, transaction, perspective, view });
return { txInfo };
};
28 changes: 28 additions & 0 deletions packages/services/src/view-service/util/transaction-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { TransactionView } from '@penumbra-zone/protobuf/penumbra/core/transaction/v1/transaction_pb';
import { getTransmissionKeyByAddress } from '@penumbra-zone/wasm/keys';

// Some transaction views (TXVs) require additional preprocessing before being rendered
// in the UI component library. For example, when handling IBC withdrawals with transparent
// addresses, this component transforms ephemeral addresses into their bech32-encoded
// transparent form to ensure the proper data is being displayed.
export const txvTranslator = async (view: TransactionView): Promise<TransactionView> => {

Check failure on line 8 in packages/services/src/view-service/util/transaction-view.ts

View workflow job for this annotation

GitHub Actions / Lint

Async arrow function 'txvTranslator' has no 'await' expression
Copy link
Contributor Author

@TalDerei TalDerei Dec 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renders the proper address format in the transaction view that's passed to the UI component library

Screenshot 2024-12-22 at 12 29 48 AM Screenshot 2024-12-22 at 12 29 39 AM

// 'Ics20Withdrawal' action view
const withdrawalAction = view?.bodyView?.actionViews?.find(

Check failure on line 10 in packages/services/src/view-service/util/transaction-view.ts

View workflow job for this annotation

GitHub Actions / Lint

Unnecessary optional chain on a non-nullish value

Check failure on line 10 in packages/services/src/view-service/util/transaction-view.ts

View workflow job for this annotation

GitHub Actions / Lint

Unnecessary optional chain on a non-nullish value
action => action.actionView.case === 'ics20Withdrawal',
);

if (withdrawalAction?.actionView.case === 'ics20Withdrawal') {
const withdrawal = withdrawalAction.actionView.value;
// Create 80-byte array initialized to zeros, then set first 32 bytes to transmission key.
// This constructs a valid address format where:
// - First 32 bytes: transmission key
// - Remaining 48 bytes: zeroed (16-byte diversifier + 32-byte clue key)
if (withdrawal.returnAddress && withdrawal.useTransparentAddress) {
const newInner = new Uint8Array(80).fill(0);
newInner.set(getTransmissionKeyByAddress(withdrawal.returnAddress), 0);
withdrawal.returnAddress.inner = newInner;
}
}

return view;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ViewBox } from '../viewbox';
import { ActionDetails } from './action-details';
import { joinLoHiAmount } from '@penumbra-zone/types/amount';
import { bech32mAddress } from '@penumbra-zone/bech32m/penumbra';
import { bech32TransparentAddress } from '@penumbra-zone/bech32m/tpenumbra';

// Converts nanoseconds timestamp to UTC timestamp string
export const getUtcTime = (time: bigint) => {
Expand Down Expand Up @@ -37,7 +38,9 @@ export const Ics20WithdrawalComponent = ({ value }: { value: Ics20Withdrawal })

{value.returnAddress && (
<ActionDetails.Row label='Return Address'>
{bech32mAddress(value.returnAddress)}
{value.useTransparentAddress
? bech32TransparentAddress({ inner: value.returnAddress.inner.slice(0, 32) })
: bech32mAddress(value.returnAddress)}
</ActionDetails.Row>
)}

Expand Down
Loading