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

feat: refactor ext API and add new NEP264 functionality #742

Merged
merged 20 commits into from
May 12, 2022
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
Prev Previous commit
Next Next commit
cleanup and remove duplication
  • Loading branch information
austinabell committed Mar 10, 2022
commit a88e9b0f2641b78f58ffb221e625135fb95c16ad
Binary file not shown.
Binary file modified examples/fungible-token/res/fungible_token.wasm
Binary file not shown.
Binary file modified examples/non-fungible-token/res/non_fungible_token.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions near-contract-standards/src/fungible_token/core.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use near_sdk::ext_contract;
use near_sdk::json_types::U128;
use near_sdk::AccountId;
use near_sdk::PromiseOrValue;

#[ext_contract(ext_ft_core)]
pub trait FungibleTokenCore {
/// Transfers positive `amount` of tokens from the `env::predecessor_account_id` to `receiver_id`.
/// Both accounts must be registered with the contract for transfer to succeed. (See [NEP-145](https://github.com/near/NEPs/discussions/145))
Expand Down
40 changes: 6 additions & 34 deletions near-contract-standards/src/fungible_token/core_impl.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,18 @@
use crate::fungible_token::core::FungibleTokenCore;
use crate::fungible_token::events::FtTransfer;
use crate::fungible_token::resolver::{fungible_token_resolver_ext, FungibleTokenResolver};
use crate::fungible_token::receiver::ext_ft_receiver;
use crate::fungible_token::resolver::{ext_ft_resolver, FungibleTokenResolver};
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::json_types::U128;
use near_sdk::{
assert_one_yocto, env, ext_contract, log, require, AccountId, Balance, Gas, IntoStorageKey,
PromiseOrValue, PromiseResult, StorageUsage,
assert_one_yocto, env, log, require, AccountId, Balance, Gas, IntoStorageKey, PromiseOrValue,
PromiseResult, StorageUsage,
};

const GAS_FOR_RESOLVE_TRANSFER: Gas = Gas(5_000_000_000_000);
const GAS_FOR_FT_TRANSFER_CALL: Gas = Gas(25_000_000_000_000 + GAS_FOR_RESOLVE_TRANSFER.0);

#[ext_contract(ext_fungible_token_receiver)]
pub trait FungibleTokenReceiver {
fn ft_on_transfer(
&mut self,
sender_id: AccountId,
amount: U128,
msg: String,
) -> PromiseOrValue<U128>;
}

#[ext_contract(ext_fungible_token)]
pub trait FungibleTokenContract {
fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128, memo: Option<String>);

fn ft_transfer_call(
&mut self,
receiver_id: AccountId,
amount: U128,
memo: Option<String>,
msg: String,
) -> PromiseOrValue<U128>;

/// Returns the total supply of the token in a decimal string representation.
fn ft_total_supply(&self) -> U128;

/// Returns the balance of the account. If the account doesn't exist, `"0"` must be returned.
fn ft_balance_of(&self, account_id: AccountId) -> U128;
}

/// Implementation of a FungibleToken standard.
/// Allows to include NEP-141 compatible token to any contract.
/// There are next traits that any contract may implement:
Expand Down Expand Up @@ -167,11 +139,11 @@ impl FungibleTokenCore for FungibleToken {
let amount: Balance = amount.into();
self.internal_transfer(&sender_id, &receiver_id, amount, memo);
// Initiating receiver's call and the callback
ext_fungible_token_receiver::ext(receiver_id.clone())
ext_ft_receiver::ext(receiver_id.clone())
.with_static_gas(env::prepaid_gas() - GAS_FOR_FT_TRANSFER_CALL)
.ft_on_transfer(sender_id.clone(), amount.into(), msg)
.then(
fungible_token_resolver_ext::ext(env::current_account_id())
ext_ft_resolver::ext(env::current_account_id())
.with_static_gas(GAS_FOR_RESOLVE_TRANSFER)
.ft_resolve_transfer(sender_id, receiver_id, amount.into()),
)
Expand Down
3 changes: 2 additions & 1 deletion near-contract-standards/src/fungible_token/receiver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use near_sdk::json_types::U128;
use near_sdk::{AccountId, PromiseOrValue};
use near_sdk::{ext_contract, AccountId, PromiseOrValue};

#[ext_contract(ext_ft_receiver)]
pub trait FungibleTokenReceiver {
/// Called by fungible token contract after `ft_transfer_call` was initiated by
/// `sender_id` of the given `amount` with the transfer message given in `msg` field.
Expand Down
2 changes: 1 addition & 1 deletion near-contract-standards/src/fungible_token/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use near_sdk::{ext_contract, json_types::U128, AccountId};

#[ext_contract(fungible_token_resolver_ext)]
#[ext_contract(ext_ft_resolver)]
pub trait FungibleTokenResolver {
fn ft_resolve_transfer(
&mut self,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::non_fungible_token::approval::ext_nft_approval_receiver;
/// Common implementation of the [approval management standard](https://nomicon.io/Standards/NonFungibleToken/ApprovalManagement.html) for NFTs.
/// on the contract/account that has just been approved. This is not required to implement.
use crate::non_fungible_token::approval::NonFungibleTokenApproval;
Expand All @@ -7,7 +8,7 @@ use crate::non_fungible_token::utils::{
refund_approved_account_ids_iter, refund_deposit,
};
use crate::non_fungible_token::NonFungibleToken;
use near_sdk::{assert_one_yocto, env, ext_contract, require, AccountId, Gas, Promise};
use near_sdk::{assert_one_yocto, env, require, AccountId, Gas, Promise};

const GAS_FOR_NFT_APPROVE: Gas = Gas(10_000_000_000_000);

Expand All @@ -19,17 +20,6 @@ fn expect_approval<T>(option: Option<T>) -> T {
option.unwrap_or_else(|| env::panic_str("next_approval_by_id must be set for approval ext"))
}

#[ext_contract(ext_approval_receiver)]
pub trait NonFungibleTokenReceiver {
fn nft_on_approve(
&mut self,
token_id: TokenId,
owner_id: AccountId,
approval_id: u64,
msg: String,
);
}

impl NonFungibleTokenApproval for NonFungibleToken {
fn nft_approve(
&mut self,
Expand Down Expand Up @@ -68,7 +58,7 @@ impl NonFungibleTokenApproval for NonFungibleToken {

// if given `msg`, schedule call to `nft_on_approve` and return it. Else, return None.
msg.map(|msg| {
ext_approval_receiver::ext(account_id)
ext_nft_approval_receiver::ext(account_id)
.with_static_gas(env::prepaid_gas() - GAS_FOR_NFT_APPROVE)
.nft_on_approve(token_id, owner_id, approval_id, msg)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::non_fungible_token::token::TokenId;
use near_sdk::AccountId;
use near_sdk::{ext_contract, AccountId};

/// Approval receiver is the trait for the method called (or attempted to be called) when an NFT contract adds an approval for an account.
#[ext_contract(ext_nft_approval_receiver)]
pub trait NonFungibleTokenApprovalReceiver {
/// Respond to notification that contract has been granted approval for a token.
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use super::resolver::NonFungibleTokenResolver;
use crate::non_fungible_token::core::receiver::ext_nft_receiver;
use crate::non_fungible_token::core::resolver::ext_nft_resolver;
use crate::non_fungible_token::core::NonFungibleTokenCore;
use crate::non_fungible_token::events::{NftMint, NftTransfer};
use crate::non_fungible_token::metadata::TokenMetadata;
Expand All @@ -10,37 +12,14 @@ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::{LookupMap, TreeMap, UnorderedSet};
use near_sdk::json_types::Base64VecU8;
use near_sdk::{
assert_one_yocto, env, ext_contract, require, AccountId, BorshStorageKey, CryptoHash,
Gas, IntoStorageKey, PromiseOrValue, PromiseResult, StorageUsage,
assert_one_yocto, env, require, AccountId, BorshStorageKey, CryptoHash, Gas, IntoStorageKey,
PromiseOrValue, PromiseResult, StorageUsage,
};
use std::collections::HashMap;

const GAS_FOR_RESOLVE_TRANSFER: Gas = Gas(5_000_000_000_000);
const GAS_FOR_NFT_TRANSFER_CALL: Gas = Gas(25_000_000_000_000 + GAS_FOR_RESOLVE_TRANSFER.0);

#[ext_contract(ext_self)]
trait NFTResolver {
fn nft_resolve_transfer(
&mut self,
previous_owner_id: AccountId,
receiver_id: AccountId,
token_id: TokenId,
approved_account_ids: Option<HashMap<AccountId, u64>>,
) -> bool;
}

#[ext_contract(ext_receiver)]
pub trait NonFungibleTokenReceiver {
/// Returns true if token should be returned to `sender_id`
fn nft_on_transfer(
&mut self,
sender_id: AccountId,
previous_owner_id: AccountId,
token_id: TokenId,
msg: String,
) -> PromiseOrValue<bool>;
}

/// Implementation of the non-fungible token standard.
/// Allows to include NEP-171 compatible token to any contract.
/// There are next traits that any contract may implement:
Expand Down Expand Up @@ -432,11 +411,11 @@ impl NonFungibleTokenCore for NonFungibleToken {
let (old_owner, old_approvals) =
self.internal_transfer(&sender_id, &receiver_id, &token_id, approval_id, memo);
// Initiating receiver's call and the callback
ext_receiver::ext(receiver_id.clone())
ext_nft_receiver::ext(receiver_id.clone())
.with_static_gas(env::prepaid_gas() - GAS_FOR_NFT_TRANSFER_CALL)
.nft_on_transfer(sender_id, old_owner.clone(), token_id.clone(), msg)
.then(
ext_self::ext(env::current_account_id())
ext_nft_resolver::ext(env::current_account_id())
.with_static_gas(GAS_FOR_RESOLVE_TRANSFER)
.nft_resolve_transfer(old_owner, receiver_id, token_id, old_approvals),
)
Expand Down
4 changes: 2 additions & 2 deletions near-contract-standards/src/non_fungible_token/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ mod resolver;

pub use self::core_impl::*;

pub use self::receiver::*;
pub use self::resolver::*;
pub use self::receiver::NonFungibleTokenReceiver;
pub use self::resolver::NonFungibleTokenResolver;

use crate::non_fungible_token::token::{Token, TokenId};
use near_sdk::AccountId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::non_fungible_token::token::TokenId;
use near_sdk::{AccountId, PromiseOrValue};
use near_sdk::{ext_contract, AccountId, PromiseOrValue};

/// Used when an NFT is transferred using `nft_transfer_call`. This trait is implemented on the receiving contract, not on the NFT contract.
#[ext_contract(ext_nft_receiver)]
pub trait NonFungibleTokenReceiver {
/// Take some action after receiving a non-fungible token
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::non_fungible_token::token::TokenId;
use near_sdk::AccountId;
use near_sdk::{ext_contract, AccountId};
use std::collections::HashMap;

/// Used when an NFT is transferred using `nft_transfer_call`. This is the method that's called after `nft_on_transfer`. This trait is implemented on the NFT contract.
#[ext_contract(ext_nft_resolver)]
pub trait NonFungibleTokenResolver {
/// Finalize an `nft_transfer_call` chain of cross-contract calls.
///
Expand Down
6 changes: 2 additions & 4 deletions near-sdk-macros/src/core_impl/code_generator/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ pub(crate) fn generate_ext_function_wrappers<'a>(

fn generate_ext_function(attr_signature_info: &AttrSigInfo) -> TokenStream2 {
let pat_type_list = attr_signature_info.pat_type_list();
let serialize = serializer::generate_serializer(
&attr_signature_info,
&attr_signature_info.input_serializer,
);
let serialize =
serializer::generate_serializer(attr_signature_info, &attr_signature_info.input_serializer);

let AttrSigInfo { non_bindgen_attrs, ident, original_sig, .. } = attr_signature_info;
let ident_str = ident.to_string();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl ItemImplInfo {
.filter(|m| m.is_public || self.is_trait_impl)
.map(|m| &m.attr_signature_info),
),
Err(e) => return syn::Error::new(self.ty.span(), e).to_compile_error(),
Err(e) => syn::Error::new(self.ty.span(), e).to_compile_error(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,3 @@ pub fn generate_sim_proxy_struct(input: &ItemStruct) -> proc_macro2::TokenStream
pub fn generate_ext_struct(input: &ItemStruct) -> proc_macro2::TokenStream {
generate_ext_structs(&input.ident, Some(&input.generics))
}


6 changes: 3 additions & 3 deletions near-sdk/src/promise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl PromiseJoint {
/// #[near_bindgen]
/// impl ContractA {
/// pub fn a(&self) -> Promise {
/// contract_b::b("bob_near".parse().unwrap(), 0, Gas(1_000))
/// contract_b::ext("bob_near".parse().unwrap()).b()
/// }
/// }
/// ```
Expand Down Expand Up @@ -416,11 +416,11 @@ impl Promise {
/// #[near_bindgen]
/// impl ContractA {
/// pub fn a1(&self) {
/// contract_b::b("bob_near".parse().unwrap(), 0, Gas(1_000)).as_return();
/// contract_b::ext("bob_near".parse().unwrap()).b().as_return();
/// }
///
/// pub fn a2(&self) -> Promise {
/// contract_b::b("bob_near".parse().unwrap(), 0, Gas(1_000))
/// contract_b::ext("bob_near".parse().unwrap()).b()
/// }
/// }
/// ```
Expand Down