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

Incoming proxy #76

Merged
merged 40 commits into from
Jan 3, 2024
Merged

Incoming proxy #76

merged 40 commits into from
Jan 3, 2024

Conversation

taitruong
Copy link
Collaborator

@taitruong taitruong commented Dec 27, 2023

Similar to outgoing proxy (for source chain), this PR adds an optional incoming proxy for target chain. In case an incoming proxy is defined, incoming IbcPacket and NonFungibleTokenPacketData is passed to proxy.

A default implementation can be found here: https://github.com/arkprotocol/cw721-proxy/tree/main/contracts/cw721-incoming-proxy

The incoming proxy validates from which channel (=chain and ics721) IbcPacket is coming from. In case channel is not whitelisted an UnauthorizedSourceChannel is thrown.

An incoming proxy is needed in case chain or ics721 on source/other chain has been compromised.

Comment on lines +72 to +78
/// Being called on receiving the NFT before transfer is completed. (destination side)
/// `on_recieve` hook
/// Note - Failing this message will fail the transfer.
Ics721ReceivePacketMsg {
packet: IbcPacket,
data: NonFungibleTokenPacketData,
},
Copy link
Collaborator Author

@taitruong taitruong Dec 27, 2023

Choose a reason for hiding this comment

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

In case optional incoming proxy is set, during ibc_packet_receive this msg is called on proxy.

packages/ics721/src/execute.rs Show resolved Hide resolved
packages/ics721/src/execute.rs Outdated Show resolved Hide resolved
let data: NonFungibleTokenPacketData = from_json(&packet.data)?;
data.validate()?;

// If there is an incoming proxy, let proxy validate the packet, in case it fails, we fail the transfer
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here's where incoming proxy is getting called on target chain. In case proxy throws an error, NFT is returned back to soure chain. For details check here: https://github.com/arkprotocol/cw721-proxy/blob/main/packages/cw-incoming-proxy/src/lib.rs#L44-L56

packages/ics721/src/testing/contract.rs Show resolved Hide resolved
@@ -2025,7 +2073,8 @@ fn test_migration() {
new_code_id: test.ics721_id,
msg: to_json_binary(&MigrateMsg::WithUpdate {
pauser: None,
proxy: None,
incoming_proxy: None,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

test migration

@@ -186,6 +244,115 @@ test.serial("transfer NFT", async (t) => {
t.is(osmoAddr, tokenOwner.owner);
});

test.serial("transfer NFT with incoming proxy: osmo -> wasmd", async (t) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

relayer test for incoming proxy with 2 scenarios:

  1. nft send to WLed channel
  2. nft send to unknown channel

nft_contract: { class_id: wasmClassId },
});

tokenOwner = await ownerOf(wasmClient, wasmCw721, tokenId);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

scenario 1: NFT received on target chain

Comment on lines 350 to 353
// assert NFT on chain A is returned to owner
tokenOwner = await ownerOf(osmoClient, osmoCw721, tokenId);
t.is(osmoClient.senderAddress, tokenOwner.owner);
t.log(`NFT #${tokenId} returned to owner`);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

scenario 2: NFT returned to source chain.

// use by default ClassId, in case there's no class data with name and symbol
let mut instantiate_msg = cw721_base::msg::InstantiateMsg {
name: class.id.clone().into(),
symbol: class.id.clone().into(),
minter: env.contract.address.to_string(),
withdraw_address: Some(creator),
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Allow creator of ics721 for setting withdraw address on nft contract (allowing to send and withdraw funds). This affected only ics721-base for permissionless chains.
sg-ics721 is unchanged.
More on withdraw address, see here: public-awesome/cw-nfts#149

}

impl<'a> Bounder<'a> for ClassId {
fn inclusive_bound(self) -> Option<cw_storage_plus::Bound<'a, Self>> {
Copy link
Contributor

Choose a reason for hiding this comment

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

What exactly is this doing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is needed in query_nft_contracts() since paginated query requires a bounder. Simple need trick for inferring a bounder: https://github.com/arkprotocol/ark-cw-ics721/blob/incoming_proxy/packages/ics721/src/query.rs#L138
Bounder defined here: https://github.com/DA0-DA0/dao-contracts/blob/v2.4.0/packages/cw-paginate-storage/src/lib.rs#L18

Copy link
Contributor

Choose a reason for hiding this comment

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

Well my question is, it seems like the code is just copy paste something that already exists? Doesn't it already get this functionality through an import? What specifically is changing in the override?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, it doesn't exist yet. If I dont implement bounder, then I have to explicitely provide bounder in query.

@taitruong
Copy link
Collaborator Author

Can a high-level description be added to this PR?

Done - description added above.

Comment on lines +279 to +281
test.serial(
"transfer NFT with osmo outgoing and wasm incoming proxy",
async (t) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NEW: added ts-relayer integration test for:

  • ics721 handles incoming msg from outgoing proxy properly
  • ics721 passes ibc packet to incoming proxy
    • success: in case packet is coming from WLed channel
    • fail: in case channel is not WLed -> NFT returned back to onwer on source chain

@taitruong taitruong requested a review from Art3miX December 31, 2023 08:17
Comment on lines 84 to -68
}) => self.execute_receive_nft(deps, env, info, token_id, sender, msg),
ExecuteMsg::ReceiveProxyNft { eyeball, msg } => {
self.execute_receive_proxy_nft(deps, env, info, eyeball, msg)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ReceiveProxyNft has been removed, instead ReceiveNft handles both: msgs from collection and outgoing proxy contract

Copy link
Collaborator

@Art3miX Art3miX left a comment

Choose a reason for hiding this comment

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

looks good

packages/ics721/src/execute.rs Show resolved Hide resolved
@taitruong taitruong added this pull request to the merge queue Jan 3, 2024
Merged via the queue into public-awesome:main with commit f1dfefc Jan 3, 2024
1 check passed
@taitruong taitruong deleted the incoming_proxy branch June 10, 2024 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants