bytepayment / bytepay

Coding to earn! Sell opensource product as NFT ~
https://bytepay.online
Apache License 2.0
11 stars 6 forks source link

project delivery - NEAR & BytePay #38

Open layla1994 opened 2 years ago

layla1994 commented 2 years ago

Bytepay

Milestone 1 — User account management & repo management & mnemonic management & Transfer contract

  1. config env
  Near cli : https://gist.github.com/think-in-universe/019671d56a949ec8a475126f22d21248
  export NEAR_CLI_MAINNET_RPC_SERVER_URL=https://public-rpc.blockpi.io/http/near
  export NEAR_ENV=mainnet

 near deploy --accountId ff3e8979eb1eac55858651bb40e51760bdfcf12ef57b1edbdd75f53fb0ed6c06 --wasmFile ./build/bytepay_contract_near.wasm
  Near cli : https://gist.github.com/think-in-universe/019671d56a949ec8a475126f22d21248
  export NEAR_CLI_TESTNET_RPC_SERVER_URL=https://public-rpc.blockpi.io/http/near-testnet
  export NEAR_ENV=testnet
  near deploy --accountId lafyun.testnet  --wasmFile ./build/bytepay_contract_near.wasm
  1. contract code
pub mod bytepay_near {
    use near_sdk::{AccountId, Balance, env, log, near_bindgen, Promise};
    use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
    use near_sdk::collections::LookupMap;

    near_sdk::setup_alloc!();

    #[near_bindgen]
    #[derive(BorshDeserialize, BorshSerialize)]
    pub struct BytePayNearContract {
        pub owner: AccountId,
        pub balances: LookupMap<AccountId, Balance>,
        pub whitelist: LookupMap<(AccountId, AccountId), Balance>,
    }

    impl Default for BytePayNearContract {
        fn default() -> Self {
            Self {
                owner: env::current_account_id(),
                balances: LookupMap::new(b"b".to_vec()),
                whitelist: LookupMap::new(b"w".to_vec()),
            }
        }
    }

    #[near_bindgen]
    impl BytePayNearContract {
        pub fn get_owner(&self) -> AccountId {
            self.owner.clone()
        }

        pub fn get_balance(&self, account: &AccountId) -> Option<Balance> {
            self.balances.get(&account)
        }

        pub fn get_whitelist(&self, current: AccountId, account: AccountId) -> Option<Balance> {
            self.whitelist.get(&(current, account))
        }

        pub fn recharge(&mut self, amount: Balance) -> &'static str {
            let signer_account = env::signer_account_id();
            let balance = self.balances.get(&signer_account).unwrap_or_default();

            Promise::new(env::current_account_id()).transfer(amount);
            self.balances.insert(&signer_account, &(amount + balance));

            "END"
        }

        pub fn set_whitelist(&mut self, account: AccountId, amount: Balance) -> &'static str {
            let signer_account = env::signer_account_id();
            let balances = self.balances.get(&signer_account).unwrap_or_default();

            if amount > balances {
                log!("INSUFFICIENT_BALANCE");
                return "INSUFFICIENT_BALANCE";
            }
            let key = (signer_account, account);
            let old = self.whitelist.get(&key).unwrap_or_default();
            self.whitelist.insert(&key, &(old + amount));

            "END"
        }

        pub fn transfer(&mut self, from: AccountId, to: AccountId, amount: Balance) -> &'static str {
            let call = env::signer_account_id();
            let current = env::current_account_id();
            if call != current {
                log!("PERMISSION_DENIED");
                return "PERMISSION_DENIED";
            }

            let key = (from.clone(), to.clone());
            let limit = self.whitelist.get(&key).unwrap_or_default();

            let zero = Balance::from('0');
            if amount < zero || (limit == zero && amount > limit) {
                log!("EXCEED_THE_LIMIT");
                return "EXCEED_THE_LIMIT";
            }

            Promise::new(to).transfer(amount);

            let balance = self.balances.get(&from).unwrap_or_default();
            self.balances.insert(&from, &(balance - amount));

            "END"
        }
    }

    /// test
    #[cfg(not(target_arch = "wasm32"))]
    #[cfg(test)]
    mod bytepay_near_test {
        use near_sdk::{testing_env, VMContext};
        use near_sdk::MockedBlockchain;

        use super::*;

       // use serde_json::to_string;

        fn get_context(input: Vec<u8>, is_view: bool) -> VMContext {
            VMContext {
                current_account_id: String::from("合约拥有者账户"),
                signer_account_id: String::from("签名账户"),
                signer_account_pk: vec![0, 1, 2],
                predecessor_account_id: String::from("前任账户"),
                input,
                block_index: 0,
                block_timestamp: 0,
                account_balance: 1000000,
                account_locked_balance: 0,
                storage_usage: 0,
                attached_deposit: 0,
                prepaid_gas: 10u64.pow(18),
                random_seed: vec![0, 1, 2],
                is_view,
                output_data_receivers: vec![],
                epoch_height: 0,
            }
        }

        /// 测试充值
        #[test]
        fn test_recharge() {
            let context = get_context(vec![], false);
            testing_env!(context);
            let mut contract = BytePayNearContract::default();
            // --------------------------------------------------------------------------
            let msg = contract.recharge(233);
            println!("回执消息: {}", msg);
            let balance = contract.get_balance(&AccountId::from("签名账户")).unwrap_or_default();
            assert_eq!(balance, 233);
        }

        /// 测试设置白名单
        #[test]
        fn test_set_whitelist() {
            let context = get_context(vec![], false);
            testing_env!(context);
            let mut contract = BytePayNearContract::default();
            // --------------------------------------------------------------------------

            let limit = 0;
            let msg = contract.set_whitelist(AccountId::from("test-account.near.org"), limit);
            println!("设置白名单回执消息: {}", msg);
            assert_eq!(msg, "END");

            let option = contract.get_whitelist(AccountId::from("签名账户"), AccountId::from("test-account.near.org"));
            assert_eq!(option.unwrap_or_default(), limit)
        }

        /// 测试转账
        #[test]
        fn test_transfer() {
            let context = get_context(vec![], false);
            testing_env!(context);
            let mut contract = BytePayNearContract::default();
            // --------------------------------------------------------------------------

            let msg = contract.transfer(env::current_account_id(), AccountId::from("test-account.near.org"), 233);
            println!("回执: {}", msg)
        }
    }
}
  1. test contract
cargo test --lib bytepay_near::bytepay_near_test::test_recharge -- --show-output
cargo test --lib bytepay_near::bytepay_near_test::test_set_whitelist -- --show-output
cargo test --lib bytepay_near::bytepay_near_test::test_transfer -- --show-output
  1. view method
View contract owner: `get_owner`

Check balance: `get_balance`

**Parameter:**

| name    | type      |
|---------|-----------|
| account | AccountId |

#### View whitelist restrictions for a specified account: `get_whitelist`

**Parameter:**

| name    | type      | description  |
|---------|-----------|--------------|
| current | AccountId | current user |
| account | AccountId | target users |

### change method

#### Recharge: `recharge`

**Parameter:**

| name   | type    | 
|--------|---------|
| amount | Balance |

#### Set up a whitelist: `set_whitelist`

**Parameter:**

| name    | type      | description       |
|---------|-----------|-------------------|
| account | AccountId | target users      |
| amount  | Balance   | target user quota |

#### The contract administrator initiates a transfer transaction: `transfer`

**Parameter:**

| name   | type      | description |
|--------|-----------|-------------|
| from   | AccountId | payer       |
| to     | AccountId | payee       |
| amount | Balance   | money       |

use `near-cli` call example:

```shell
near view <contract_account> get_balance '{"account": "account.testnet"}'

Milestone 2 — Transfer module, task module, informal, withdraw module

Create a paid task by comment an issue, it will trigger the create task event through the webhook, and the webhook server will save the task and show it on our page, when the developer complete the task, will trigger transfer module to pay the developer p p

  1. bob apply this task

/bytepay apply p

  1. /bytepay task pay

/bytepay pay p