Is there a way to check inside the smart contract (in Rust) if another account has a smart-contract associated with it and implements some interface?
In particular, in this function I would like to check if a recipient is a smart contract and if it has a required method:
trait FTReceiver {
fn on_nft_receive(&self, sender: AddressID, token: AddressID) -> bool;
}
pub fn transfer(&mut self, recipient: AccountID, reference: String) {
// note: env::* functions below don't exist!
if env::has_smart_contract(recipient) && env::ctr_implements(recipient, FTReceiver) {
Promise::new(token.clone()).function_call(
"on_ft_receive".into(),
&serde_json::to_vec(&json!({
"sender": env::predecessor_account_id() /*...*/
})),
);
}
}
The only way to check that is try & fail approach:
Unfortunately this is complex and we can't handle the edge cases. We can't check in a reliable way why a
Promisefailed. The promise can fail because of: A) an account doesn't have a smart-contract, B) smart-contract doesn't have a called function C) function failure (eg assertion fail). This limitation is described in Simulation Tests repository: Error messages early in promise execution. Simulation tests are using exactly same runtime code as the blockchain.Workaround
As @vlad-frolow noticed, we smart contracts can use
viewmethods to report their interface. At the time of writing there is no standard for this view methods.One idea:
Note:
There is an ongoing work to inspect external accounts in the NEAR runtime.