create-near-app 8.5.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +2 -1
- package/dist/make.js +7 -27
- package/dist/messages.js +1 -9
- package/dist/types.js +3 -2
- package/dist/user-input.js +32 -13
- package/dist/utils/index.js +1 -3
- package/package.json +2 -1
- package/templates/contracts/auction/rs/Cargo.toml +57 -0
- package/templates/contracts/auction/rs/README.md +39 -0
- package/templates/contracts/auction/rs/rust-toolchain.toml +4 -0
- package/templates/contracts/auction/rs/src/lib.rs +118 -0
- package/templates/contracts/auction/rs/tests/test_basics.rs +182 -0
- package/templates/contracts/auction/ts/README.md +47 -0
- package/templates/contracts/auction/ts/package.json +22 -0
- package/templates/contracts/auction/ts/sandbox-test/main.ava.js +88 -0
- package/templates/contracts/auction/ts/src/contract.ts +72 -0
- package/templates/contracts/auction/ts/tsconfig.json +14 -0
- package/templates/contracts/{rs → auction-adv/rs}/Cargo.toml +9 -7
- package/templates/contracts/auction-adv/rs/README.md +35 -0
- package/templates/contracts/{rs → auction-adv/rs}/rust-toolchain.toml +1 -1
- package/templates/contracts/auction-adv/rs/src/ext.rs +17 -0
- package/templates/contracts/auction-adv/rs/src/lib.rs +159 -0
- package/templates/contracts/auction-adv/rs/tests/fungible_token.wasm +0 -0
- package/templates/contracts/auction-adv/rs/tests/non_fungible_token.wasm +0 -0
- package/templates/contracts/auction-adv/rs/tests/test_basics.rs +430 -0
- package/templates/contracts/auction-adv/ts/README.md +45 -0
- package/templates/contracts/auction-adv/ts/package.json +22 -0
- package/templates/contracts/auction-adv/ts/sandbox-test/fungible_token.wasm +0 -0
- package/templates/contracts/auction-adv/ts/sandbox-test/main.ava.js +165 -0
- package/templates/contracts/auction-adv/ts/sandbox-test/non_fungible_token.wasm +0 -0
- package/templates/contracts/auction-adv/ts/src/contract.ts +87 -0
- package/templates/frontend/next-app/package.json +2 -28
- package/templates/frontend/next-app/src/app/hello-near/page.tsx +2 -4
- package/templates/frontend/next-app/src/app/layout.tsx +3 -58
- package/templates/frontend/next-app/src/components/navigation.tsx +14 -14
- package/templates/frontend/next-page/package.json +3 -24
- package/templates/frontend/next-page/src/components/cards.tsx +0 -1
- package/templates/frontend/next-page/src/components/navigation.tsx +14 -14
- package/templates/frontend/next-page/src/pages/_app.tsx +3 -56
- package/templates/frontend/next-page/src/pages/hello-near/index.tsx +2 -2
- package/templates/frontend/vite-react/package.json +6 -28
- package/templates/frontend/vite-react/src/App.tsx +3 -62
- package/templates/frontend/vite-react/src/components/navigation.tsx +13 -19
- package/templates/frontend/vite-react/src/global.d.ts +13 -0
- package/templates/frontend/vite-react/src/pages/hello_near.tsx +3 -3
- package/templates/contracts/py/.python-version +0 -1
- package/templates/contracts/py/README.md +0 -74
- package/templates/contracts/py/contract.py +0 -31
- package/templates/contracts/py/pyproject.toml +0 -10
- package/templates/contracts/py/tests/test_mod.py +0 -53
- package/templates/contracts/py/uv.lock +0 -878
- package/templates/contracts/rs/.github/workflows/deploy-production.yml +0 -25
- package/templates/contracts/rs/.github/workflows/deploy-staging.yml +0 -52
- package/templates/contracts/rs/.github/workflows/test.yml +0 -34
- package/templates/contracts/rs/.github/workflows/undeploy-staging.yml +0 -23
- package/templates/contracts/rs/README.md +0 -43
- package/templates/contracts/rs/src/lib.rs +0 -55
- package/templates/contracts/rs/tests/test_basics.rs +0 -30
- package/templates/contracts/ts/README.md +0 -83
- package/templates/contracts/ts/package.json +0 -23
- package/templates/contracts/ts/sandbox-test/main.ava.js +0 -45
- package/templates/contracts/ts/src/contract.ts +0 -23
- package/templates/contracts/ts/yarn.lock +0 -3290
- package/templates/frontend/next-app/src/wallets/web3modal.ts +0 -27
- package/templates/frontend/next-page/src/wallets/web3modal.ts +0 -27
- package/templates/frontend/vite-react/src/wallets/web3modal.ts +0 -27
- /package/templates/contracts/{ts → auction-adv/ts}/tsconfig.json +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Basic Auction Contract
|
|
2
|
+
|
|
3
|
+
This directory contains a JavaScript contract that is used as part of the [Basic Auction Tutorial](https://docs.near.org/tutorials/auction/basic-auction).
|
|
4
|
+
|
|
5
|
+
The contract is a simple auction where you can place bids, view the highest bid, and claim the tokens at the end of the auction.
|
|
6
|
+
|
|
7
|
+
This repo showcases the basic anatomy of a contract including how to store data in a contract, how to update the state, and then how to view it. It also looks at how to use environment variables and macros. We have also written sandbox test the contract locally.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## How to Build Locally?
|
|
12
|
+
|
|
13
|
+
Install the [NEAR CLI](https://docs.near.org/tools/near-cli#installation) and run:
|
|
14
|
+
|
|
15
|
+
Install the dependencies:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Build the contract:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How to Test Locally?
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## How to Deploy?
|
|
34
|
+
|
|
35
|
+
Install the [NEAR CLI](https://docs.near.org/tools/near-cli#installation) and run:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Create a new account
|
|
39
|
+
near create <contractId> --useFaucet
|
|
40
|
+
|
|
41
|
+
# Deploy the contract
|
|
42
|
+
near deploy <contractId> ./build/auction-contract.wasm
|
|
43
|
+
|
|
44
|
+
# Initialize the contract
|
|
45
|
+
TWO_MINUTES_FROM_NOW=$(date -v+2M +%s000000000)
|
|
46
|
+
near call <contractId> init '{"end_time": "'$TWO_MINUTES_FROM_NOW'", "auctioneer": "<auctioneerAccountId>"}' --accountId <contractId>
|
|
47
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "auction-contract",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "(MIT AND Apache-2.0)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "near-sdk-js build src/contract.ts build/auction-contract.wasm",
|
|
8
|
+
"test": "$npm_execpath run build && ava -- ./build/auction-contract.wasm"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"near-sdk-js": "2.0.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"ava": "^6.1.3",
|
|
15
|
+
"near-workspaces": "^3.5.0",
|
|
16
|
+
"typescript": "^5.4.5"
|
|
17
|
+
},
|
|
18
|
+
"ava": {
|
|
19
|
+
"timeout": "50000",
|
|
20
|
+
"files": ["sandbox-test/*.ava.js"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import anyTest from 'ava';
|
|
2
|
+
import { NEAR, Worker } from 'near-workspaces';
|
|
3
|
+
import { setDefaultResultOrder } from 'dns'; setDefaultResultOrder('ipv4first'); // temp fix for node >v17
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('near-workspaces').NearAccount} NearAccount
|
|
7
|
+
* @type {import('ava').TestFn<{worker: Worker, accounts: Record<string, NearAccount>}>}
|
|
8
|
+
*/
|
|
9
|
+
const test = anyTest;
|
|
10
|
+
test.beforeEach(async (t) => {
|
|
11
|
+
// Init the worker and start a Sandbox server
|
|
12
|
+
const worker = t.context.worker = await Worker.init();
|
|
13
|
+
|
|
14
|
+
// Create accounts
|
|
15
|
+
const root = worker.rootAccount;
|
|
16
|
+
|
|
17
|
+
const alice = await root.createSubAccount("alice", { initialBalance: NEAR.parse("10 N").toString() });
|
|
18
|
+
const bob = await root.createSubAccount("bob", { initialBalance: NEAR.parse("10 N").toString() });
|
|
19
|
+
const auctioneer = await root.createSubAccount("auctioneer", { initialBalance: NEAR.parse("10 N").toString() });
|
|
20
|
+
const contract = await root.createSubAccount("contract", { initialBalance: NEAR.parse("10 N").toString() });
|
|
21
|
+
|
|
22
|
+
// Deploy contract (input from package.json)
|
|
23
|
+
await contract.deploy(process.argv[2]);
|
|
24
|
+
|
|
25
|
+
// Initialize contract, finishes in 1 minute
|
|
26
|
+
await contract.call(contract, "init", {
|
|
27
|
+
end_time: String((Date.now() + 60000) * 10 ** 6),
|
|
28
|
+
auctioneer: auctioneer.accountId,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Save state for test runs, it is unique for each test
|
|
32
|
+
t.context.worker = worker;
|
|
33
|
+
t.context.accounts = { alice, bob, contract, auctioneer };
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test.afterEach.always(async (t) => {
|
|
37
|
+
// Stop Sandbox server
|
|
38
|
+
await t.context.worker.tearDown().catch((error) => {
|
|
39
|
+
console.log('Failed to stop the Sandbox:', error);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("Test full contract", async (t) => {
|
|
44
|
+
const { alice, bob, auctioneer, contract } = t.context.accounts;
|
|
45
|
+
|
|
46
|
+
// Alice makes first bid
|
|
47
|
+
await alice.call(contract, "bid", {}, { attachedDeposit: NEAR.parse("1 N").toString() });
|
|
48
|
+
let highest_bid = await contract.view("get_highest_bid", {});
|
|
49
|
+
t.is(highest_bid.bidder, alice.accountId);
|
|
50
|
+
t.is(highest_bid.bid, NEAR.parse("1 N").toString());
|
|
51
|
+
const aliceBalance = await alice.balance();
|
|
52
|
+
|
|
53
|
+
// Bob makes a higher bid
|
|
54
|
+
await bob.call(contract, "bid", {}, { attachedDeposit: NEAR.parse("2 N").toString() });
|
|
55
|
+
highest_bid = await contract.view("get_highest_bid", {});
|
|
56
|
+
t.is(highest_bid.bidder, bob.accountId);
|
|
57
|
+
t.is(highest_bid.bid, NEAR.parse("2 N").toString());
|
|
58
|
+
|
|
59
|
+
// Check that alice was returned her bid
|
|
60
|
+
const aliceNewBalance = await alice.balance();
|
|
61
|
+
t.deepEqual(aliceNewBalance.available, aliceBalance.available.add(NEAR.parse("1 N")));
|
|
62
|
+
|
|
63
|
+
// Alice tires to make a bid with less NEAR than the previous
|
|
64
|
+
await t.throwsAsync(alice.call(contract, "bid", {}, { attachedDeposit: NEAR.parse("1 N").toString() }));
|
|
65
|
+
|
|
66
|
+
// Auctioneer claims auction but did not finish
|
|
67
|
+
await t.throwsAsync(auctioneer.call(contract, "claim", {}, { gas: "300000000000000" }));
|
|
68
|
+
|
|
69
|
+
// Fast forward 200 blocks
|
|
70
|
+
await t.context.worker.provider.fastForward(200)
|
|
71
|
+
|
|
72
|
+
const auctioneerBalance = await auctioneer.balance();
|
|
73
|
+
const available = parseFloat(auctioneerBalance.available.toHuman());
|
|
74
|
+
|
|
75
|
+
// Auctioneer claims the auction
|
|
76
|
+
await auctioneer.call(contract, "claim", {}, { gas: "300000000000000" });
|
|
77
|
+
|
|
78
|
+
// Checks that the auctioneer has the correct balance
|
|
79
|
+
const contractNewBalance = await auctioneer.balance();
|
|
80
|
+
const new_available = parseFloat(contractNewBalance.available.toHuman());
|
|
81
|
+
t.is(new_available.toFixed(1), (available + 2).toFixed(1));
|
|
82
|
+
|
|
83
|
+
// Auctioneer tries to claim the auction again
|
|
84
|
+
await t.throwsAsync(auctioneer.call(contract, "claim", {}, { gas: "300000000000000" }))
|
|
85
|
+
|
|
86
|
+
// Alice tries to make a bid when the auction is over
|
|
87
|
+
await t.throwsAsync(alice.call(contract, "bid", {}, { attachedDeposit: NEAR.parse("1 N").toString() }));
|
|
88
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Find all our documentation at https://docs.near.org
|
|
2
|
+
import { NearBindgen, near, call, view, AccountId, NearPromise, initialize, assert } from "near-sdk-js";
|
|
3
|
+
|
|
4
|
+
class Bid {
|
|
5
|
+
bidder: AccountId;
|
|
6
|
+
bid: bigint;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@NearBindgen({ requireInit: true })
|
|
10
|
+
class AuctionContract {
|
|
11
|
+
highest_bid: Bid = { bidder: '', bid: BigInt(0) };
|
|
12
|
+
auction_end_time: bigint = BigInt(0);
|
|
13
|
+
auctioneer: AccountId = "";
|
|
14
|
+
claimed: boolean = false;
|
|
15
|
+
|
|
16
|
+
@initialize({ privateFunction: true })
|
|
17
|
+
init({ end_time, auctioneer}: { end_time: bigint, auctioneer: AccountId}) {
|
|
18
|
+
this.auction_end_time = end_time;
|
|
19
|
+
this.highest_bid = { bidder: near.currentAccountId(), bid: BigInt(1) };
|
|
20
|
+
this.auctioneer = auctioneer;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@call({ payableFunction: true })
|
|
24
|
+
bid(): NearPromise {
|
|
25
|
+
// Assert the auction is still ongoing
|
|
26
|
+
assert(this.auction_end_time > near.blockTimestamp(), "Auction has ended");
|
|
27
|
+
|
|
28
|
+
// Current bid
|
|
29
|
+
const bid = near.attachedDeposit();
|
|
30
|
+
const bidder = near.predecessorAccountId();
|
|
31
|
+
|
|
32
|
+
// Last bid
|
|
33
|
+
const { bidder: lastBidder, bid: lastBid } = this.highest_bid;
|
|
34
|
+
|
|
35
|
+
// Check if the deposit is higher than the current bid
|
|
36
|
+
assert(bid > lastBid, "You must place a higher bid");
|
|
37
|
+
|
|
38
|
+
// Update the highest bid
|
|
39
|
+
this.highest_bid = { bidder, bid }; // Save the new bid
|
|
40
|
+
|
|
41
|
+
// Transfer tokens back to the last bidder
|
|
42
|
+
return NearPromise.new(lastBidder).transfer(lastBid);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@call({})
|
|
46
|
+
claim() {
|
|
47
|
+
assert(this.auction_end_time <= near.blockTimestamp(), "Auction has not ended yet");
|
|
48
|
+
assert(!this.claimed, "Auction has been claimed");
|
|
49
|
+
this.claimed = true;
|
|
50
|
+
return NearPromise.new(this.auctioneer).transfer(this.highest_bid.bid)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@view({})
|
|
54
|
+
get_highest_bid(): Bid {
|
|
55
|
+
return this.highest_bid;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@view({})
|
|
59
|
+
get_auction_end_time(): BigInt {
|
|
60
|
+
return this.auction_end_time;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@view({})
|
|
64
|
+
get_auctioneer(): AccountId {
|
|
65
|
+
return this.auctioneer;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@view({})
|
|
69
|
+
get_claimed(): boolean {
|
|
70
|
+
return this.claimed;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "
|
|
2
|
+
name = "cargo-near-new-project-name"
|
|
3
3
|
description = "cargo-near-new-project-description"
|
|
4
4
|
version = "0.1.0"
|
|
5
5
|
edition = "2021"
|
|
@@ -15,9 +15,9 @@ crate-type = ["cdylib", "rlib"]
|
|
|
15
15
|
# in https://github.com/near/NEPs/blob/master/neps/nep-0330.md
|
|
16
16
|
[package.metadata.near.reproducible_build]
|
|
17
17
|
# docker image, descriptor of build environment
|
|
18
|
-
image = "sourcescan/cargo-near:0.
|
|
18
|
+
image = "sourcescan/cargo-near:0.18.0-rust-1.86.0"
|
|
19
19
|
# tag after colon above serves only descriptive purpose; image is identified by digest
|
|
20
|
-
image_digest = "sha256:
|
|
20
|
+
image_digest = "sha256:2d0d458d2357277df669eac6fa23a1ac922e5ed16646e1d3315336e4dff18043"
|
|
21
21
|
# list of environment variables names, whose values, if set, will be used as external build parameters
|
|
22
22
|
# in a reproducible manner
|
|
23
23
|
# supported by `sourcescan/cargo-near:0.10.1-rust-1.82.0` image or later images
|
|
@@ -36,13 +36,15 @@ container_build_command = [
|
|
|
36
36
|
|
|
37
37
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
38
38
|
[dependencies]
|
|
39
|
-
near-sdk = "5.
|
|
39
|
+
near-sdk = "5.23"
|
|
40
40
|
|
|
41
41
|
[dev-dependencies]
|
|
42
|
-
near-sdk = { version = "5.
|
|
43
|
-
near-
|
|
42
|
+
near-sdk = { version = "5.23", features = ["unit-testing"] }
|
|
43
|
+
near-sandbox = "0.3"
|
|
44
|
+
near-api = "0.8"
|
|
45
|
+
cargo-near-build = "0.9.0"
|
|
44
46
|
tokio = { version = "1.12.0", features = ["full"] }
|
|
45
|
-
|
|
47
|
+
testresult = "0.4.1"
|
|
46
48
|
|
|
47
49
|
[profile.release]
|
|
48
50
|
codegen-units = 1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Auction contract with FTs
|
|
2
|
+
|
|
3
|
+
This directory contains a Rust contract that is used as part of the [Bidding with FTs](https://docs.near.org/tutorials/auction/bidding-with-fts) section of the auction tutorial.
|
|
4
|
+
|
|
5
|
+
In this part the contract is adapted so users can bid in fungible tokens (FTs) instead of NEAR tokens. It is a great way to learn how to work with FTs in NEAR.
|
|
6
|
+
|
|
7
|
+
## How to Build Locally?
|
|
8
|
+
|
|
9
|
+
Install [`cargo-near`](https://github.com/near/cargo-near) and run:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cargo near build
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## How to Test Locally?
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cargo test
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to Deploy?
|
|
22
|
+
|
|
23
|
+
To deploy manually, install [NEAR CLI](https://docs.near.org/tools/near-cli#installation) and run:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Create a new account
|
|
27
|
+
near create <contractId> --useFaucet
|
|
28
|
+
|
|
29
|
+
# Deploy the contract on it
|
|
30
|
+
near deploy <contractId> ./target/near/auction-contract.wasm
|
|
31
|
+
|
|
32
|
+
# Initialize the contract
|
|
33
|
+
TWO_MINUTES_FROM_NOW=$(date -v+2M +%s000000000)
|
|
34
|
+
near call <contractId> init '{"end_time": "'$TWO_MINUTES_FROM_NOW'", "auctioneer": "<auctioneerAccountId>", "ft_contract": "<ftContractId>", "nft_contract": "<nftContractId>", "token_id": "<tokenId>", "starting_price": "<startingPrice>"}' --accountId <contractId>
|
|
35
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Find all our documentation at https://docs.near.org
|
|
2
|
+
use near_sdk::json_types::U128;
|
|
3
|
+
use near_sdk::{ext_contract, AccountId};
|
|
4
|
+
|
|
5
|
+
use crate::TokenId;
|
|
6
|
+
|
|
7
|
+
// FT interface for cross-contract calls
|
|
8
|
+
#[ext_contract(ft_contract)]
|
|
9
|
+
trait FT {
|
|
10
|
+
fn ft_transfer(&self, receiver_id: AccountId, amount: U128);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// NFT interface for cross-contract calls
|
|
14
|
+
#[ext_contract(nft_contract)]
|
|
15
|
+
trait NFT {
|
|
16
|
+
fn nft_transfer(&self, receiver_id: AccountId, token_id: TokenId);
|
|
17
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Find all our documentation at https://docs.near.org
|
|
2
|
+
use near_sdk::json_types::{U128, U64};
|
|
3
|
+
use near_sdk::{env, near, require, AccountId, Gas, NearToken, PanicOnDefault};
|
|
4
|
+
|
|
5
|
+
pub mod ext;
|
|
6
|
+
pub use crate::ext::*;
|
|
7
|
+
|
|
8
|
+
#[near(serializers = [json, borsh])]
|
|
9
|
+
#[derive(Clone)]
|
|
10
|
+
pub struct Bid {
|
|
11
|
+
pub bidder: AccountId,
|
|
12
|
+
pub bid: U128,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub type TokenId = String;
|
|
16
|
+
|
|
17
|
+
#[near(contract_state, serializers = [json, borsh])]
|
|
18
|
+
#[derive(PanicOnDefault)]
|
|
19
|
+
pub struct Contract {
|
|
20
|
+
highest_bid: Bid,
|
|
21
|
+
auction_end_time: U64,
|
|
22
|
+
auctioneer: AccountId,
|
|
23
|
+
claimed: bool,
|
|
24
|
+
ft_contract: AccountId,
|
|
25
|
+
nft_contract: AccountId,
|
|
26
|
+
token_id: TokenId,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[near]
|
|
30
|
+
impl Contract {
|
|
31
|
+
#[init]
|
|
32
|
+
#[private] // only callable by the contract's account
|
|
33
|
+
pub fn init(
|
|
34
|
+
end_time: U64,
|
|
35
|
+
auctioneer: AccountId,
|
|
36
|
+
ft_contract: AccountId,
|
|
37
|
+
nft_contract: AccountId,
|
|
38
|
+
token_id: TokenId,
|
|
39
|
+
starting_price: U128,
|
|
40
|
+
) -> Self {
|
|
41
|
+
Self {
|
|
42
|
+
highest_bid: Bid {
|
|
43
|
+
bidder: env::current_account_id(),
|
|
44
|
+
bid: starting_price,
|
|
45
|
+
},
|
|
46
|
+
auction_end_time: end_time,
|
|
47
|
+
auctioneer,
|
|
48
|
+
claimed: false,
|
|
49
|
+
ft_contract,
|
|
50
|
+
nft_contract,
|
|
51
|
+
token_id,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Users bid by transferring FT tokens
|
|
56
|
+
pub fn ft_on_transfer(&mut self, sender_id: AccountId, amount: U128, msg: String) -> U128 {
|
|
57
|
+
require!(
|
|
58
|
+
env::block_timestamp() < self.auction_end_time.into(),
|
|
59
|
+
"Auction has ended"
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
let ft = env::predecessor_account_id();
|
|
63
|
+
require!(ft == self.ft_contract, "The token is not supported");
|
|
64
|
+
|
|
65
|
+
// Last bid
|
|
66
|
+
let Bid {
|
|
67
|
+
bidder: last_bidder,
|
|
68
|
+
bid: last_bid,
|
|
69
|
+
} = self.highest_bid.clone();
|
|
70
|
+
|
|
71
|
+
// Check if the deposit is higher than the current bid
|
|
72
|
+
require!(amount > last_bid, "You must place a higher bid");
|
|
73
|
+
|
|
74
|
+
// Update the highest bid
|
|
75
|
+
self.highest_bid = Bid {
|
|
76
|
+
bidder: sender_id,
|
|
77
|
+
bid: amount,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Transfer FTs back to the last bidder
|
|
81
|
+
let _ = ft_contract::ext(self.ft_contract.clone())
|
|
82
|
+
.with_attached_deposit(NearToken::from_yoctonear(1))
|
|
83
|
+
.with_static_gas(Gas::from_tgas(30))
|
|
84
|
+
.ft_transfer(last_bidder, last_bid);
|
|
85
|
+
|
|
86
|
+
U128(0)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn claim(&mut self) {
|
|
90
|
+
require!(
|
|
91
|
+
env::block_timestamp() > self.auction_end_time.into(),
|
|
92
|
+
"Auction has not ended yet"
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
require!(!self.claimed, "Auction has been claimed");
|
|
96
|
+
|
|
97
|
+
self.claimed = true;
|
|
98
|
+
|
|
99
|
+
// Transfer FTs to the auctioneer
|
|
100
|
+
// Assumes the auctioneer account is already registered with the FT contract
|
|
101
|
+
let _ = ft_contract::ext(self.ft_contract.clone())
|
|
102
|
+
.with_attached_deposit(NearToken::from_yoctonear(1))
|
|
103
|
+
.with_static_gas(Gas::from_tgas(30))
|
|
104
|
+
.ft_transfer(self.auctioneer.clone(), self.highest_bid.bid);
|
|
105
|
+
|
|
106
|
+
// Transfer the NFT to the highest bidder
|
|
107
|
+
let _ = nft_contract::ext(self.nft_contract.clone())
|
|
108
|
+
.with_static_gas(Gas::from_tgas(30))
|
|
109
|
+
.with_attached_deposit(NearToken::from_yoctonear(1))
|
|
110
|
+
.nft_transfer(self.highest_bid.bidder.clone(), self.token_id.clone());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pub fn get_highest_bid(&self) -> Bid {
|
|
114
|
+
self.highest_bid.clone()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub fn get_auction_end_time(&self) -> U64 {
|
|
118
|
+
self.auction_end_time
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pub fn get_auction_info(&self) -> &Contract {
|
|
122
|
+
self
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[cfg(test)]
|
|
127
|
+
mod tests {
|
|
128
|
+
use super::*;
|
|
129
|
+
|
|
130
|
+
#[test]
|
|
131
|
+
fn init_contract() {
|
|
132
|
+
let end_time: U64 = U64::from(1000);
|
|
133
|
+
let alice: AccountId = "alice.near".parse().unwrap();
|
|
134
|
+
let ft_contract: AccountId = "ft.near".parse().unwrap();
|
|
135
|
+
let nft_contract: AccountId = "nft.near".parse().unwrap();
|
|
136
|
+
let token_id: TokenId = "1".to_string();
|
|
137
|
+
let starting_price: U128 = U128(100);
|
|
138
|
+
let contract = Contract::init(
|
|
139
|
+
end_time.clone(),
|
|
140
|
+
alice.clone(),
|
|
141
|
+
ft_contract.clone(),
|
|
142
|
+
nft_contract.clone(),
|
|
143
|
+
token_id.clone(),
|
|
144
|
+
starting_price.clone(),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
let default_bid = contract.get_highest_bid();
|
|
148
|
+
assert_eq!(default_bid.bidder, env::current_account_id());
|
|
149
|
+
assert_eq!(default_bid.bid, starting_price);
|
|
150
|
+
|
|
151
|
+
let auction_info = contract.get_auction_info();
|
|
152
|
+
assert_eq!(auction_info.auction_end_time, end_time);
|
|
153
|
+
assert_eq!(auction_info.auctioneer, alice);
|
|
154
|
+
assert_eq!(auction_info.ft_contract, ft_contract);
|
|
155
|
+
assert_eq!(auction_info.nft_contract, nft_contract);
|
|
156
|
+
assert_eq!(auction_info.token_id, token_id);
|
|
157
|
+
assert_eq!(auction_info.claimed, false);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
Binary file
|
|
Binary file
|