FT-master
    README.md
    ft
        Cargo.toml
        build_docker.sh
        src
            aml.rs
            fungible_token
                core_impl.rs
                core_token.rs
                event.rs
                events.rs
                macros.rs
                metadata.rs
                mod.rs
                receiver.rs
                resolver.rs
                storage_impl.rs
            lib.rs
            owner.rs
    integration-tests
        rs
            Cargo.toml
            src
                tests.rs
    scripts
        build.sh
README.md

# Hapi integration example

We have a couple of examples of integrating [HAPI protocol](https://hapi-one.gitbook.io/) in a smart contract.

But firstly let's understand how it works, and what it changes.

You can use HAPI for any calls on your contract.

For example, using it in the standard fungible token.

![scheme1](img/scheme1.png)

After the call to the contract, the contract makes a call to AML, receives a response from it, and depending on the result, completes its function.

In the example with a token: an account with a high level of risk will not be able to send tokens.

Another example: is an exchange platform that does not accept exchange tokens from a high-risk account.

In your smart contract You can set the level for all categories, and individual for each one separately.

## What is categories and risk score? 

HAPI protocol contains addresses of the following categories:

| Category | Description |
|----------|-------|
| None | |
| WalletService | Wallet service - custodial or mixed wallets |
| MerchantService | Merchant service |
| MiningPool | Mining pool |
| Exchange | Low-risk exchange - Exchange with high KYC standards |
| DeFi | DeFi application |
| OTCBroker | OTC Broker |
| ATM | Cryptocurrency ATM |
| Gambling | Gambling |
| IllicitOrganization | Illicit organization |
| Mixer | Mixer |
| DarknetService | Darknet market or service |
| Scam | Scam |
| Ransomware | Ransomware |
| Theft | Theft - stolen funds |
| Counterfeit | Counterfeit - fake assets |
| TerroristFinancing | Terrorist financing |
| Sanctions | Addresses of the sanctioned individuals and organizations |
| ChildAbuse | Child abuse and porn materials |

If the address belongs to some category, it will have a
Risk score (on a scale from 0..10, i.e. max risk).

Address of the [contract](https://github.com/HAPIprotocol/near-proxy-contract) on the **testnet**

```
hapi-test.testnet
```
Address of the contract on the **mainnet**

```
proxy.hapiprotocol.near
```

## What to do for using hapi? 

1. Add [hapi-near-connector](https://crates.io/crates/hapi-near-connector) to dependencies of your project in Cargo.toml
```
[dependencies]
...
hapi-near-connector = "0.1"
```

2. Add use hapi in your lib.rs file
```
use hapi_near_connector::aml::*;
```

3. Add AML struct to your Contract struct
![img1](img/img1.png)

4. Add "AML new" to init of your contract

>Note. Here we set the accepted risk level as MAX_RISK_LEVEL/2 i.e 10/2 = 5. 
```
aml: AML::new(aml_account_id, MAX_RISK_LEVEL/2)
```

5. Add cross-contract call to the method on which we need to use hapi. 
* *ext_aml* - it's hapi's trait. 
* In get_address pass accountId you want to check. 
* *ext_self* - is the trait that will be created in the next step. 
* cb_ft_tranfer - is the method for callback after aml.
```rust
fn ft_transfer(
        &mut self,
        receiver_id: AccountId,
        amount: U128,
        memo: Option<String>,
) -> Promise {
    assert_one_yocto();
    let sender: AccountId = predecessor_account_id();
    ext_aml::ext(self.aml.get_account())
        .with_static_gas(AML_CHECK_GAS)
        .get_address(sender.clone())
        .then(
            ext_self::ext(current_account_id())
                .with_static_gas(CALLBACK_AML_GAS)
                .cb_ft_transfer(sender, receiver_id, amount, memo),
        )
}
```

6. Create a trait with a callback
```rust
#[ext_contract(ext_self)]
pub trait ExtContract {
    /// Callback after ft_transfer.
    fn cb_ft_transfer(
        &mut self,
        sender_id: AccountId,
        #[callback] category_risk: CategoryRisk,
        receiver_id: AccountId,
        amount: U128,
        memo: Option<String>,
    );
}
```

After that, your contract can already work with Hapi.

If you need to change the accepted risk level for *All* categories or add a new one, use *update_category*.

```rust
fn update_category(&mut self, category: Category, risk_score: RiskScore) {
    self.assert_owner();
    self.aml.update_category(category, risk_score);
}
```

Also, you can delete an added category. Then it will be evaluated in the *All* category.
>Note. You can't delete the category *All*.

```rust
fn remove_category(&mut self, category: Category) {
    self.assert_owner();
    self.aml.remove_category(category);
}
```

## Integration HAPI in already deployed contract
------------------

For the integration of HAPI in an already deployed contract, you should do the previous steps, and add a method that migrates your old contract struct to a new struct that includes HAPI.

```rust
pub trait Migrations {
    fn add_hapi(aml_account_id: AccountId) -> Self;
}

#[near_bindgen]
impl Migrations for Contract {
    #[private]
    #[init(ignore_state)]
    #[allow(dead_code)]
    fn add_hapi(aml_account_id: AccountId) -> Self {
        #[derive(BorshDeserialize)]
        pub struct OldContract {
            token: FungibleToken,
            metadata: LazyOption<FungibleTokenMetadata>,
            owner_id: AccountId,
        }

        let old_contract: OldContract = env::state_read().expect("Old state doesn't exist");

        Self {
            token: old_contract.token,
            metadata: old_contract.metadata,
            owner_id: old_contract.owner_id,
            aml: AML::new(aml_account_id, MAX_RISK_LEVEL / 2),
        }
    }
}
```

Then you need to rebuild and redeploy the new wasm. Migrate your contract with the command
```bash
near call $CONTRACT_ID add_hapi '{"aml_account_id": "'$AML_ID'"}' --accountId $CONTRACT_ID
```

Now your contract is ready to work with HAPI. And you can remove the *Migrations* trait from your contract.
Fungible Token (FT)
===================

Example implementation of a [Fungible Token] contract which uses [near-contract-standards] and [simulation] tests. This is a contract-only example.

  [Fungible Token]: https://nomicon.io/Standards/FungibleToken/Core
  [near-contract-standards]: https://github.com/near/near-sdk-rs/tree/master/near-contract-standards
  [simulation]: https://github.com/near/near-sdk-rs/tree/master/near-sdk-sim

## Building

To build run:
```bash
./scripts/build.sh
```

Using this contract
===================

### Quickest deploy

You can build and deploy this smart contract to a development account. [Dev Accounts](https://docs.near.org/concepts/basics/account#dev-accounts) are auto-generated accounts to assist in developing and testing smart contracts. Please see the [Standard deploy](#standard-deploy) section for creating a more personalized account to deploy to.

```bash
near dev-deploy --wasmFile res/fungible_token.wasm --helperUrl https://near-contract-helper.onrender.com
```

Behind the scenes, this is creating an account and deploying a contract to it. On the console, notice a message like:

>Done deploying to dev-1234567890123

In this instance, the account is `dev-1234567890123`. A file has been created containing a key pair to
the account, located at `neardev/dev-account`. To make the next few steps easier, we're going to set an
environment variable containing this development account id and use that when copy/pasting commands.
Run this command to the environment variable:

export NEAR_ENV=testnet
export OWNER_ID=hapi-test.testnet
export CONTRACT_ID=token.$OWNER_ID
export AML_ID=contract.$OWNER_ID

```bash
source neardev/dev-account.env
```

You can tell if the environment variable is set correctly if your command line prints the account name after this command:
```bash
echo $CONTRACT_NAME
```

The next command will initialize the contract using the `new` method:

```bash
near call $CONTRACT_ID new '{"owner_id": "'$OWNER_ID'", "total_supply": "1000000000000000000000000000000000", "metadata": { "spec": "ft-1.0.0", "name": "Hapi powered token", "symbol": "HAPI", "decimals": 18 }, "aml_account_id": "'$AML_ID'"}' --accountId $CONTRACT_ID
```

To get the fungible token metadata:

```bash
near view $CONTRACT_NAME ft_metadata
```

### Standard deploy

This smart contract will get deployed to your NEAR account. For this example, please create a new NEAR account. Because NEAR allows the ability to upgrade contracts on the same account, initialization functions must be cleared. If you'd like to run this example on a NEAR account that has had prior contracts deployed, please use the `near-cli` command `near delete`, and then recreate it in Wallet. To create (or recreate) an account, please follow the directions on [NEAR Wallet](https://wallet.near.org/).

Switch to `mainnet`. You can skip this step to use `testnet` as a default network.

    export NEAR_ENV=mainnet

In the project root, log in to your newly created account  with `near-cli` by following the instructions after this command:

    near login

To make this tutorial easier to copy/paste, we're going to set an environment variable for your account id. In the below command, replace `MY_ACCOUNT_NAME` with the account name you just logged in with, including the `.near`:

    ID=MY_ACCOUNT_NAME

You can tell if the environment variable is set correctly if your command line prints the account name after this command:

    echo $ID

Now we can deploy the compiled contract in this example to your account:

    near deploy --wasmFile res/fungible_token.wasm --accountId $ID

FT contract should be initialized before usage. You can read more about metadata at ['nomicon.io'](https://nomicon.io/Standards/FungibleToken/Metadata.html#reference-level-explanation). Modify the parameters and create a token:

    near call $ID new '{"owner_id": "'$ID'", "total_supply": "1000000000000000", "metadata": { "spec": "ft-1.0.0", "name": "Example Token Name", "symbol": "EXLT", "decimals": 8 }}' --accountId $ID

Get metadata:

    near view $ID ft_metadata

Transfer Example
---------------

Let's set up an account to transfer some tokens to. These account will be a sub-account of the NEAR account you logged in with.

    near create-account bob.$ID --masterAccount $ID --initialBalance 1

Add storage deposit for Bob's account:

    near call $ID storage_deposit '' --accountId bob.$ID --amount 0.00125

Check balance of Bob's account, it should be `0` for now:

    near view $ID ft_balance_of '{"account_id": "'bob.$ID'"}'

Transfer tokens to Bob from the contract that minted these fungible tokens, exactly 1 yoctoNEAR of deposit should be attached:

    near call $ID ft_transfer '{"receiver_id": "'bob.$ID'", "amount": "19"}' --accountId $ID --amount 0.000000000000000000000001

near deploy token.hapi-test.testnet --wasmFile=res/hapi_token_release.wasm
