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

Update the token-actor interface #75

Merged
merged 10 commits into from
Aug 23, 2022

Conversation

alexytsu
Copy link
Member

filecoin-project/FIPs#407 should be sync'd with the new interface/types defined here

@alexytsu alexytsu force-pushed the token/interface-updates branch 3 times, most recently from 2d170f8 to 712da5f Compare August 18, 2022 04:38
self.util.transfer(&spender, &spender, &params.to, &params.amount, &params.data)?;

// FIXME: populate with real values
Ok(TransferReturn { from_balance: TokenAmount::zero(), to_balance: TokenAmount::zero() })
Copy link
Member Author

Choose a reason for hiding this comment

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

might be more efficient if Token::transfer returned the relevant info, else we can make separate calls to Token::balance_of and Token::allowance etc.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed. Simple but maybe error-prone would be to return an anonymous tuple. Another alternative is to return the Return types defined earlier, but that inverts the expected dependency hierarchy. Another option is separate return structs, but they'll be a bit duplicative.

@alexytsu alexytsu requested a review from anorth August 18, 2022 05:15
Copy link
Collaborator

@anorth anorth left a comment

Choose a reason for hiding this comment

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

Great improvement, thanks.

fil_fungible_token/src/receiver/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
self.util.transfer(&spender, &spender, &params.to, &params.amount, &params.data)?;

// FIXME: populate with real values
Ok(TransferReturn { from_balance: TokenAmount::zero(), to_balance: TokenAmount::zero() })
Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed. Simple but maybe error-prone would be to return an anonymous tuple. Another alternative is to return the Return types defined earlier, but that inverts the expected dependency hierarchy. Another option is separate return structs, but they'll be a bit duplicative.

@alexytsu alexytsu requested a review from abright August 22, 2022 07:27
@alexytsu alexytsu marked this pull request as ready for review August 22, 2022 07:28
fil_fungible_token/src/receiver/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/types.rs Outdated Show resolved Hide resolved
Comment on lines 632 to 687
#[derive(Debug)]
pub enum TransferResult {
Transfer(TransferReturn),
TransferFrom(TransferFromReturn),
}

impl TryFrom<TransferResult> for TransferFromReturn {
type Error = TokenError;

fn try_from(value: TransferResult) -> Result<TransferFromReturn> {
match value {
TransferResult::TransferFrom(ret) => Ok(ret),
TransferResult::Transfer(_) => Err(TokenError::TransferReturn { result: value }),
}
}
}

impl TryFrom<TransferResult> for TransferReturn {
type Error = TokenError;

fn try_from(value: TransferResult) -> Result<TransferReturn> {
match value {
TransferResult::TransferFrom(_) => Err(TokenError::TransferReturn { result: value }),
TransferResult::Transfer(ret) => Ok(ret),
}
}
}

#[derive(Debug)]
pub enum BurnResult {
Burn(BurnReturn),
BurnFrom(BurnFromReturn),
}

impl TryFrom<BurnResult> for BurnReturn {
type Error = TokenError;

fn try_from(value: BurnResult) -> Result<Self> {
match value {
BurnResult::Burn(ret) => Ok(ret),
BurnResult::BurnFrom(_) => Err(TokenError::BurnReturn { result: value }),
}
}
}

impl TryFrom<BurnResult> for BurnFromReturn {
type Error = TokenError;

fn try_from(value: BurnResult) -> Result<Self> {
match value {
BurnResult::BurnFrom(ret) => Ok(ret),
BurnResult::Burn(_) => Err(TokenError::BurnReturn { result: value }),
}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

An alternative to this might be to have separate library level methods for transfer and transfer_from which return different types that match the FRC interface

Copy link
Collaborator

Choose a reason for hiding this comment

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

This enum technique seems like it's trying too hard, and the Err cases are weird. If we're going to have this much code anyway, I think the naive duplication might be better.

fil_fungible_token/src/receiver/types.rs Outdated Show resolved Hide resolved
fil_fungible_token/src/token/mod.rs Show resolved Hide resolved
Comment on lines 632 to 687
#[derive(Debug)]
pub enum TransferResult {
Transfer(TransferReturn),
TransferFrom(TransferFromReturn),
}

impl TryFrom<TransferResult> for TransferFromReturn {
type Error = TokenError;

fn try_from(value: TransferResult) -> Result<TransferFromReturn> {
match value {
TransferResult::TransferFrom(ret) => Ok(ret),
TransferResult::Transfer(_) => Err(TokenError::TransferReturn { result: value }),
}
}
}

impl TryFrom<TransferResult> for TransferReturn {
type Error = TokenError;

fn try_from(value: TransferResult) -> Result<TransferReturn> {
match value {
TransferResult::TransferFrom(_) => Err(TokenError::TransferReturn { result: value }),
TransferResult::Transfer(ret) => Ok(ret),
}
}
}

#[derive(Debug)]
pub enum BurnResult {
Burn(BurnReturn),
BurnFrom(BurnFromReturn),
}

impl TryFrom<BurnResult> for BurnReturn {
type Error = TokenError;

fn try_from(value: BurnResult) -> Result<Self> {
match value {
BurnResult::Burn(ret) => Ok(ret),
BurnResult::BurnFrom(_) => Err(TokenError::BurnReturn { result: value }),
}
}
}

impl TryFrom<BurnResult> for BurnFromReturn {
type Error = TokenError;

fn try_from(value: BurnResult) -> Result<Self> {
match value {
BurnResult::BurnFrom(ret) => Ok(ret),
BurnResult::Burn(_) => Err(TokenError::BurnReturn { result: value }),
}
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

This enum technique seems like it's trying too hard, and the Err cases are weird. If we're going to have this much code anyway, I think the naive duplication might be better.

fil_fungible_token/src/token/mod.rs Outdated Show resolved Hide resolved
@@ -18,172 +18,205 @@ pub enum ActorError<Err> {
pub type Result<T, E> = std::result::Result<T, ActorError<E>>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will be tricky for users to implement, primarily because of the ActorError type defined here. E.g. the builtin actors already return a Result<T, ActorError> but my ActorError is a different type than this. Can this trait be fully generic over the result's error type?

Also, we don't strictly need this trait. It's helpful to ensure full implementation, but I've done fine without it. If we can't get it to be universally helpful to users, we could drop it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll do some thinking and experimenting around this but deferred for a followup

@alexytsu alexytsu merged commit 4940dfb into token/basic-example Aug 23, 2022
@alexytsu alexytsu deleted the token/interface-updates branch August 23, 2022 05:35
abright pushed a commit that referenced this pull request Aug 25, 2022
* update the public token-actor interface

* update example actor to match new interface

* check receiver hooks

* cleanup naming

* align with FRC-0046

* fix CI build

* exclude wasm actors from code coverage

* rearrange params

* use RawBytes rather than Default

* split burn/burn_from transfer/transfer_from
abright added a commit that referenced this pull request Aug 25, 2022
* add integration test contract

* write example basic token actor

* wip

* add build script for example actor

* update example actor to latest token api

* lock fvm version for example actor test

also disables default features because we don't need GPU support (or the dependencies that brings) for running tests

* add fil_integration_tests to Makefile

* pretty-print the message results in token actor test

* use a helper function to simplify messaging in tests

* add a barebones actor to implement a receiver hook

* extend the mint implementation and mint tokens to the receiver actor

* Update the token-actor interface (#75)

* update the public token-actor interface

* update example actor to match new interface

* check receiver hooks

* cleanup naming

* align with FRC-0046

* fix CI build

* exclude wasm actors from code coverage

* rearrange params

* use RawBytes rather than Default

* split burn/burn_from transfer/transfer_from

* Split receiver hook calls from minting and transfer - part 1 (#76)

* wip: split minting and receiver hook calling, save state at actor level

* simplify call_receiver_hook

* don't try to reset state on minting failure, let invoke deal with it

* set a panic hook to use the vm::abort like built-in actors do

this means we'll get back meaningful errors if an unwrap() explodes

* token code cleanup

* gracefully handle empty return data on minting failure in mint_tokens test

* further cleanup

* use a more appropriate error code for "unknown method" abort

* split receiver hook call out of transfer and transfer_from

* remove call_receiver_hook_or_revert

* ignore failing mint/transfer tests

They're expecting the old behaviour of reverting state (instead of aborting) when a mint or transfer (or receiver hook) fails. Once there's a new method of calling the receiver hook (through a type returned by mint or transfer calls) they can either be adapted to that or rewritten as integration tests

* update dispatch crate name

* code cleanup

* set_root after flushing state in method calls, so the state tree is kept up to date

Co-authored-by: Andrew Bright <abright@users.noreply.github.com>
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.

None yet

2 participants