create-near-app 8.4.1 → 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.
Files changed (92) hide show
  1. package/dist/app.js +2 -1
  2. package/dist/make.js +7 -27
  3. package/dist/messages.js +1 -9
  4. package/dist/types.js +3 -2
  5. package/dist/user-input.js +32 -13
  6. package/dist/utils/index.js +1 -3
  7. package/package.json +2 -1
  8. package/templates/contracts/auction/rs/Cargo.toml +57 -0
  9. package/templates/contracts/auction/rs/README.md +39 -0
  10. package/templates/contracts/auction/rs/rust-toolchain.toml +4 -0
  11. package/templates/contracts/auction/rs/src/lib.rs +118 -0
  12. package/templates/contracts/auction/rs/tests/test_basics.rs +182 -0
  13. package/templates/contracts/auction/ts/README.md +47 -0
  14. package/templates/contracts/auction/ts/package.json +22 -0
  15. package/templates/contracts/auction/ts/sandbox-test/main.ava.js +88 -0
  16. package/templates/contracts/auction/ts/src/contract.ts +72 -0
  17. package/templates/contracts/auction/ts/tsconfig.json +14 -0
  18. package/templates/contracts/{rs → auction-adv/rs}/Cargo.toml +9 -7
  19. package/templates/contracts/auction-adv/rs/README.md +35 -0
  20. package/templates/contracts/{rs → auction-adv/rs}/rust-toolchain.toml +1 -1
  21. package/templates/contracts/auction-adv/rs/src/ext.rs +17 -0
  22. package/templates/contracts/auction-adv/rs/src/lib.rs +159 -0
  23. package/templates/contracts/auction-adv/rs/tests/fungible_token.wasm +0 -0
  24. package/templates/contracts/auction-adv/rs/tests/non_fungible_token.wasm +0 -0
  25. package/templates/contracts/auction-adv/rs/tests/test_basics.rs +430 -0
  26. package/templates/contracts/auction-adv/ts/README.md +45 -0
  27. package/templates/contracts/auction-adv/ts/package.json +22 -0
  28. package/templates/contracts/auction-adv/ts/sandbox-test/fungible_token.wasm +0 -0
  29. package/templates/contracts/auction-adv/ts/sandbox-test/main.ava.js +165 -0
  30. package/templates/contracts/auction-adv/ts/sandbox-test/non_fungible_token.wasm +0 -0
  31. package/templates/contracts/auction-adv/ts/src/contract.ts +87 -0
  32. package/templates/frontend/next-app/next-env.d.ts +6 -0
  33. package/templates/frontend/next-app/package.json +8 -22
  34. package/templates/frontend/{next-page/src/pages/hello-near/index.js → next-app/src/app/hello-near/page.tsx} +22 -21
  35. package/templates/frontend/next-app/src/app/layout.tsx +25 -0
  36. package/templates/frontend/next-app/src/components/{cards.js → cards.tsx} +4 -9
  37. package/templates/frontend/next-app/src/components/navigation.tsx +45 -0
  38. package/templates/frontend/next-app/tsconfig.json +42 -0
  39. package/templates/frontend/next-page/next-env.d.ts +6 -0
  40. package/templates/frontend/next-page/package.json +8 -22
  41. package/templates/frontend/next-page/src/components/{cards.js → cards.tsx} +0 -1
  42. package/templates/frontend/next-page/src/components/navigation.tsx +45 -0
  43. package/templates/frontend/next-page/src/pages/_app.tsx +15 -0
  44. package/templates/frontend/{vite-react/src/pages/hello_near.jsx → next-page/src/pages/hello-near/index.tsx} +18 -16
  45. package/templates/frontend/next-page/src/pages/{index.js → index.tsx} +8 -8
  46. package/templates/frontend/next-page/tsconfig.json +35 -0
  47. package/templates/frontend/vite-react/eslint.config.js +4 -1
  48. package/templates/frontend/vite-react/package.json +8 -25
  49. package/templates/frontend/vite-react/src/App.tsx +22 -0
  50. package/templates/frontend/vite-react/src/components/{cards.jsx → cards.tsx} +4 -4
  51. package/templates/frontend/vite-react/src/components/navigation.tsx +43 -0
  52. package/templates/frontend/vite-react/src/{config.js → config.ts} +1 -1
  53. package/templates/frontend/vite-react/src/global.d.ts +13 -0
  54. package/templates/frontend/vite-react/src/main.tsx +14 -0
  55. package/templates/frontend/vite-react/src/pages/hello_near.tsx +95 -0
  56. package/templates/frontend/vite-react/tsconfig.json +35 -0
  57. package/templates/contracts/py/.python-version +0 -1
  58. package/templates/contracts/py/README.md +0 -74
  59. package/templates/contracts/py/contract.py +0 -31
  60. package/templates/contracts/py/pyproject.toml +0 -10
  61. package/templates/contracts/py/tests/test_mod.py +0 -53
  62. package/templates/contracts/py/uv.lock +0 -878
  63. package/templates/contracts/rs/.github/workflows/deploy-production.yml +0 -25
  64. package/templates/contracts/rs/.github/workflows/deploy-staging.yml +0 -52
  65. package/templates/contracts/rs/.github/workflows/test.yml +0 -34
  66. package/templates/contracts/rs/.github/workflows/undeploy-staging.yml +0 -23
  67. package/templates/contracts/rs/README.md +0 -43
  68. package/templates/contracts/rs/src/lib.rs +0 -55
  69. package/templates/contracts/rs/tests/test_basics.rs +0 -30
  70. package/templates/contracts/ts/README.md +0 -83
  71. package/templates/contracts/ts/package.json +0 -23
  72. package/templates/contracts/ts/sandbox-test/main.ava.js +0 -45
  73. package/templates/contracts/ts/src/contract.ts +0 -23
  74. package/templates/contracts/ts/yarn.lock +0 -3290
  75. package/templates/frontend/next-app/jsconfig.json +0 -7
  76. package/templates/frontend/next-app/src/app/hello-near/page.js +0 -67
  77. package/templates/frontend/next-app/src/app/layout.js +0 -54
  78. package/templates/frontend/next-app/src/components/navigation.js +0 -35
  79. package/templates/frontend/next-app/src/wallets/web3modal.js +0 -27
  80. package/templates/frontend/next-page/jsconfig.json +0 -7
  81. package/templates/frontend/next-page/src/components/navigation.js +0 -35
  82. package/templates/frontend/next-page/src/pages/_app.js +0 -45
  83. package/templates/frontend/next-page/src/wallets/web3modal.js +0 -27
  84. package/templates/frontend/vite-react/src/App.jsx +0 -56
  85. package/templates/frontend/vite-react/src/components/navigation.jsx +0 -37
  86. package/templates/frontend/vite-react/src/main.jsx +0 -11
  87. package/templates/frontend/vite-react/src/wallets/web3modal.js +0 -27
  88. /package/templates/contracts/{ts → auction-adv/ts}/tsconfig.json +0 -0
  89. /package/templates/frontend/next-app/src/app/{page.js → page.tsx} +0 -0
  90. /package/templates/frontend/next-app/src/{config.js → config.ts} +0 -0
  91. /package/templates/frontend/next-page/src/{config.js → config.ts} +0 -0
  92. /package/templates/frontend/vite-react/src/pages/{home.jsx → home.tsx} +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
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "experimentalDecorators": true,
4
+ "target": "ES5",
5
+ "noEmit": true,
6
+ "noImplicitAny": false,
7
+ },
8
+ "files": [
9
+ "src/contract.ts"
10
+ ],
11
+ "exclude": [
12
+ "node_modules"
13
+ ],
14
+ }
@@ -1,5 +1,5 @@
1
1
  [package]
2
- name = "hello-rs"
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.16.0-rust-1.86.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:3220302ebb7036c1942e772810f21edd9381edf9a339983da43487c77fbad488"
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.14"
39
+ near-sdk = "5.23"
40
40
 
41
41
  [dev-dependencies]
42
- near-sdk = { version = "5.14", features = ["unit-testing"] }
43
- near-workspaces = { version = "0.20", features = ["unstable"] }
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
- serde_json = "1"
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
+ ```
@@ -1,4 +1,4 @@
1
1
  [toolchain]
2
2
  channel = "1.86.0"
3
3
  components = ["rustfmt", "clippy", "rust-analyzer"]
4
- targets = ["wasm32-unknown-unknown"]
4
+ targets = ["wasm32-unknown-unknown"]
@@ -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
+ }