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

Invalid CosmWasm Core Contract Implementation of TransferFees Payload #4211

Open
joelsmith-2019 opened this issue Jan 7, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@joelsmith-2019
Copy link
Collaborator

I was looking through the white papers to determine how the TransferFees payload should be structured and noticed it did not match the implementation in the CosmWasm Core Contract.

Links:

If you notice in the whitepaper, it defines the struct with the Amount first and then the Recipient. However, the CosmWasm Core Contract defines the structure as Recipient first and then Amount.

@evan-gray
Copy link
Contributor

Worth noting that there are likely other implementations of this governance across the other runtimes. For example, Solana appears to conform to the whitepaper.

pub struct GovernancePayloadTransferFees {
// Amount to be transferred
pub amount: U256,
// Recipient
pub to: ForeignAddress,
}

@evan-gray
Copy link
Contributor

Other implementations

✅ Algorand

[a.load() == Int(4), Seq([
off.store(off.load() + Int(1)),
MagicAssert(tchain.load() == Bytes("base16", "0008")),
off.store(off.load() + Int(26)),
fee.store(Btoi(Extract(Txn.application_args[1], off.load(), Int(8)))),
off.store(off.load() + Int(8)),
dest.store(Extract(Txn.application_args[1], off.load(), Int(32))),
InnerTxnBuilder.Begin(),
InnerTxnBuilder.SetFields(
{
TxnField.type_enum: TxnType.Payment,
TxnField.receiver: dest.load(),
TxnField.amount: fee.load(),
TxnField.fee: Int(0),
}
),
InnerTxnBuilder.Submit(),
])]

❓ Aptos

I couldn't immediately find where SetMessageFee or TransferFees are handled.

❌ CosmWasm

impl TransferFee {
pub fn deserialize(data: &[u8], fee_denom: String) -> StdResult<Self> {
let recipient = data.get_address(0);
let (_, amount) = data.get_u256(32);
let amount = Coin {
denom: fee_denom,
amount: Uint128::new(amount),
};
Ok(TransferFee { amount, recipient })
}
}

✅ Ethereum

/// @dev Parse a transferFees (action 4) with minimal validation
function parseTransferFees(bytes memory encodedTransferFees) public pure returns (TransferFees memory tf) {
uint index = 0;
tf.module = encodedTransferFees.toBytes32(index);
index += 32;
tf.action = encodedTransferFees.toUint8(index);
index += 1;
require(tf.action == 4, "invalid TransferFees");
tf.chain = encodedTransferFees.toUint16(index);
index += 2;
tf.amount = encodedTransferFees.toUint256(index);
index += 32;
tf.recipient = encodedTransferFees.toBytes32(index);
index += 32;
require(encodedTransferFees.length == index, "invalid TransferFees");
}

✅ Near

fn handle_transfer_fee(
self: &mut Wormhole,
_vaa: &state::ParsedVAA,
payload: &[u8],
deposit: Balance,
) -> PromiseOrValue<bool> {
let (_, amount) = payload.get_u256(0);
let destination = payload.get_bytes32(32).to_vec();
if amount > self.bank {
env::panic_str("bankUnderFlow");
}
// We only support addresses 32 bytes or shorter... No, we don't
// support hash addresses in this governance message
let d = AccountId::new_unchecked(get_string_from_32(&destination));
if (deposit + amount) > 0 {
self.bank -= amount;
PromiseOrValue::Promise(Promise::new(d).transfer(deposit + amount))
} else {
PromiseOrValue::Value(true)
}
}

✅ Solana

pub struct GovernancePayloadTransferFees {
// Amount to be transferred
pub amount: U256,
// Recipient
pub to: ForeignAddress,
}

✅ Sui

fun deserialize(payload: vector<u8>): TransferFee {
let cur = cursor::new(payload);
// This amount cannot be greater than max u64.
let amount = bytes32::to_u64_be(bytes32::take_bytes(&mut cur));
// Recipient must be non-zero address.
let recipient = external_address::take_nonzero(&mut cur);
cursor::destroy_empty(cur);
TransferFee {
amount: (amount as u64),
recipient: external_address::to_address(recipient)
}
}

❌ Terra

To be expected, as this was the source for CosmWasm

impl TransferFee {
pub fn deserialize(data: &[u8]) -> StdResult<Self> {
let recipient = data.get_address(0);
let (_, amount) = data.get_u256(32);
let amount = Coin {
denom: String::from(FEE_DENOMINATION),
amount: Uint128::new(amount),
};
Ok(TransferFee { amount, recipient })
}
}

❔ Wormchain Module

Unsupported

default:
return nil, types.ErrUnknownGovernanceAction

@joelsmith-2019 joelsmith-2019 changed the title Invalid Core Contract Implementation of TransferFees Payload Invalid CosmWasm Core Contract Implementation of TransferFees Payload Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants