> ## Documentation Index
> Fetch the complete documentation index at: https://docs.near.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Bidding with FTs

> Learn how to enable bidding with fungible tokens

export const Github = ({url, start, end, fname, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const startLine = start ? Number(start) : 1;
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="rounded-[0.625rem] border border-[#d0d7de] dark:border-[#30363d] overflow-hidden my-5 text-[0.8125rem] font-mono shadow-sm dark:shadow-[0_4px_24px_rgba(0,0,0,0.18)]">

      {}
      <div className="flex items-center justify-between py-2 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-b border-[#d0d7de] dark:border-[#30363d]">
        <div className="flex items-center gap-2 text-[#656d76] dark:text-[#8b949e]">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
          </svg>
          <span className="text-xs font-medium text-[#1f2328] dark:text-[#e6edf3]">
            {fileName}
          </span>
        </div>
        {start && end && <span className="text-[0.6875rem] text-[#656d76] dark:text-[#8b949e] bg-[#eaeef2] dark:bg-[#21262d] border border-[#d0d7de] dark:border-[#30363d] rounded-full py-0.5 px-2">
            Lines {start}–{end}
          </span>}
      </div>

      {}
      <div className="overflow-auto max-h-[480px] bg-white dark:bg-[#0d1117] [&_tr]:border-b-0 [&_td]:border-b-0">
        {code === null ? <div className="py-5 px-4 text-xs text-[#656d76] dark:text-[#6e7681]">
            Loading...
          </div> : <table className="w-full border-collapse leading-[1.6]">
            <tbody>
              {code.split('\n').map((line, i) => <tr key={i} className="align-top border-0">
                  <td style={{
    minWidth: '60px'
  }} className="select-none pl-2 pr-3 text-right text-[0.7rem] text-[#8c959f] dark:text-[#3d444d] w-[1%] whitespace-nowrap border-r border-0 border-r-[#d0d7de] dark:border-r-[#21262d]">
                    {startLine + i}
                  </td>
                  <td className="pl-4 pr-6 text-[0.8125rem] text-[#1f2328] dark:text-[#e6edf3] whitespace-pre">
                    {line || ' '}
                  </td>
                </tr>)}
            </tbody>
          </table>}
      </div>

      {}
      {withSourceLink && <div className="flex justify-end py-1.5 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-t border-[#d0d7de] dark:border-[#21262d]">
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] dark:text-[#8b949e] no-underline flex items-center gap-[0.3rem] hover:text-[#1f2328] dark:hover:text-[#e6edf3] transition-colors">
            View on GitHub
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
              <polyline points="15 3 21 3 21 9" />
              <line x1="10" y1="14" x2="21" y2="3" />
            </svg>
          </a>
        </div>}
    </div>;
};

To further develop this contract we will introduce another primitive: [fungible tokens](/primitives/ft/ft). Instead of placing bids in `$NEAR` tokens, they will be placed in FTs. This may be useful if, for example, an auctioneer wants to keep the bid amounts constant in terms of dollars as an auction is carried out, so bids can be placed in stablecoins such as $USDC. Another use case is if a project like Ref Finance was holding its own auction and wanted the auction to happen in its project's token $REF.

***

## Specifying the FT contract

We want to only accept bids in one type of fungible token; accepting many different FTs would make the value of each bid difficult to compare. We're also going to adjust the contract so that the auctioneer can specify a starting bid amount for the auction.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="contract.ts" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L23-L30" start="23" end="30" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L33-L53" start="33" end="53" />
  </Tab>
</Tabs>

***

## Accepting bids in FTs

When we were making bids in `$NEAR` tokens we would call the auction contract directly and attach `$NEAR` tokens to the call. With fungible tokens, since an account's balance lives on a separate contract, we call the FT contract which then calls the auction contract and transfers tokens. The method on the FT contract to do this is named `ft_transfer_call` and it will always call a method in the target contract named `ft_on_transfer`. Take a look [here](/primitives/ft/ft#attaching-fts-to-a-call) for more information.

<img src="https://mintcdn.com/neardocs/qO2GD-gji1aakHqN/assets/docs/web3-apps/tutorials/mastering-near/auction-ft-transfer.png?fit=max&auto=format&n=qO2GD-gji1aakHqN&q=85&s=bf68a9cd5ea37cecbeabb312aed0c254" alt="ft_transfer_call-flow" width="2277" height="480" data-path="assets/docs/web3-apps/tutorials/mastering-near/auction-ft-transfer.png" />

The `ft_on_transfer` method always has the same interface; the FT contract will pass it the `sender`, the `amount` of FTs being sent and a `msg` which can be empty (which it will be here) or it can contain some information needed by the method (if you want to send multiple arguments in msg it is best practice to deliver this in JSON then parse it in the contract). The method returns the number of tokens to refund the user, in our case we will use all the tokens attached to the call for the bid unless the contract panics in which case the user will automatically be refunded their FTs in full.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="contract.ts" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L33" start="33" end="33" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L56" start="56" end="56" />
  </Tab>
</Tabs>

We need to confirm that the user is attaching fungible tokens when calling the method and that they are using the right FT, this is done by checking the predecessor's account ID. Since it's the FT contract that directly calls the auction contract, the `predecessor` is now the account ID of the FT contract.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="contract.ts" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L38" start="38" end="38" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L62-L63" start="62" end="63" />
  </Tab>
</Tabs>

The bidder's account ID is now given by the argument `sender_id` and the bid amount is passed as an argument named `amount`.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="contract.ts" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L40-L43" start="40" end="43" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L75-L78" start="75" end="78" />
  </Tab>
</Tabs>

When we want to return the funds to the previous bidder we now make a cross-contract call to the FT contract.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="call" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L45-L51" start="45" end="51" />

    <Github fname="callback" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L78-L81" start="68" end="71" />

    In JavaScript, we have to return the Promise to transfer the FTs but we also need to return how much to refund the user. So after transferring the FTs, we make a `callback` to our own contract to resume the contract flow. Note that the callback is private so it can only be called by the contract. We return 0 because the method uses all the FTs in the call.
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L81-L84" start="81" end="84" />

    <Github fname="ext.rs" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/ext.rs#L8-L11" start="8" end="11" />

    We then return 0 because the method uses all the FTs in the call.

    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L86" start="86" end="86" />
  </Tab>
</Tabs>

If the call was to fail the FT contract will automatically refund the user their FTs.

<Accordion title="What happens if the cross-contract call fails?">
  The first time this method is called the contract will try to send itself FTs. Most fungible token contracts don't allow one to send themselves FTs so the cross-contract call will fail. However, since cross-contract calls are asynchronous and independent and we are not checking the result of the call then the auction contract does not care that the call failed and ft\_on\_transfer will complete successfully.

  In the other cases, the call to the fungible token contract could only fail if the receiver does not exist, the FT contract does not exist, the auction contract doesn't have enough fungible tokens to cover the amount being sent, or the receiver is not registered in the FT contract. Our contract is set up such that these errors cannot occur, the receiver must exist since they placed the previous bid, the FT contract exists since it was used to place the bid, the auction contract has enough FTs to cover the amount since it was sent that amount by the previous bid, and the receiver must be registered in the FT contract since they needed to have held the token in the first place to make a bid.
</Accordion>

***

## Claiming the FTs

When the auction is complete we need to send the fungible tokens to the auctioneer when we send the NFT to the highest bidder, we implement a similar call as when we were returning the funds just changing the arguments.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="contract.ts" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/src/contract.ts#L61-L65" start="61" end="65" />

    In JavaScript, since we need to return each cross-contract call we chain the NFT and FT transfer.
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="lib.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/src/lib.rs#L99-L109" start="99" end="109" />
  </Tab>
</Tabs>

***

## Creating a new FT

Just as with the NFT contract, we will deploy an FT contract in the sandbox tests using a WASM file compiled from [this repo](https://github.com/near-examples/FT).

When the contract is deployed it is initialized with `new_default_meta` which sets the token's metadata, including things like its name and symbol, to default values while requiring the owner (where the token supply will sent), and the total supply of the token.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L28-L29" start="28" end="29" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="test_basics.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L33-L46" start="33" end="46" />
  </Tab>
</Tabs>

***

## Registering users in the FT contract

For one to receive fungible tokens, first their account ID must be [registered](/primitives/ft/ft#registering-a-user) in the FT contract. A user has to register in an FT contract to pay for the storage used to track their amount of tokens. By default, a contract pays for its own storage, but not requiring a user to register and pay for storage would drain the contract of `$NEAR` tokens. When the contract is live we don't need to register the accounts that we transfer tokens back to since to make a bid in the first place they would have needed to be registered, but we do need to register the auction contract in the FT contract to receive bids and the auctioneer to receive the funds at the end of the auction. It is most convenient to register users from the frontend rather than the contract.

In our tests, since we are creating a new fungible token and new accounts we will actually have to register every account that will interact with FTs.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L50-L53" start="50" end="53" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="test_basics.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L81-L97" start="81" end="97" />
  </Tab>
</Tabs>

***

## Simple FT transfer to bidders

Then we will transfer the bidders FTs so they can use them to bid. A simple transfer of FTs is done using the method `ft_transfer` on the FT contract.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L56-L57" start="56" end="57" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="Call ft_transfer" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L100-L107" start="100" end="107" />

    <Github fname="ft_transfer definition" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L291-L307" start="291" end="307" />
  </Tab>
</Tabs>

***

## FT transfer call

As stated previously, to bid on the auction the bidder now calls `ft_transfer_call` on the FT contract which subsequently calls the auction contract's `ft_on_transfer` method with fungible tokens attached.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L101-L104" start="101" end="104" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="Call ft_transfer_call" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L149-L161" start="149" end="161" />

    <Github fname="ft_transfer_call definition" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L322-L337" start="322" end="337" />
  </Tab>
</Tabs>

***

## Checking users' FT balance

Previously, to check a user's `$NEAR` balance, we pulled the details from their account. Now we are using FTs we query the balance on the FT contract using `ft_balance_of`, let's check that the contract's balance increased by the bid amount and the user's balance decreased by the bid amount.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L106-L109" start="106" end="109" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="Call ft_balance_of" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L163-L166" start="163" end="166" />

    <Github fname="ft_balance_of definition" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L309-L320" start="309" end="320" />
  </Tab>
</Tabs>

***

## Invalid FT transfer call

If we make a lower bid than the previous this will cause the auction contract to panic. One might expect that `ft_transfer_call` will fail, but it does not. `ft_on_transfer` will fail and the FT contract will recognize this and reverse the transfer of tokens. So after making an invalid bid, we should check that the call was successful but the parties involved in the transaction (the bidder and the contract) have the same balance of fungible tokens as they did before the call.

Previous to this, Bob made a bid of 60,000 and Alice was returned her bid bringing her balance back up to 150,000. Now when Alice makes an invalid of 50,000 Alice's balance should remain at 150,000 and the contract should remain at a balance of 60,000.

<Tabs>
  <Tab title="🌐 JavaScript">
    <Github fname="main.ava.js" language="javascript" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/03-bid-with-fts/sandbox-test/main.ava.js#L122-L130" start="122" end="130" />
  </Tab>

  <Tab title="🦀 Rust">
    <Github fname="test_basics.rs" language="rust" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/03-bid-with-fts/tests/test_basics.rs#L190-L207" start="190" end="207" />
  </Tab>
</Tabs>

***

## Using FTs with the CLI

If you want to interact with the auction contract you're going to need FTs. For this example, we'll use \$DAI where the contract address is `dai.fakes.testnet`. One can easily acquire FTs through the [testnet faucet](https://near-faucet.io/). Select DAI and withdraw to the account you will use to place a bid. If you take a look at the transaction details you can see that the faucet registers your account in the FT contract and then sends you DAI from the faucet account.

When deploying the contract make sure to specify the FT contract `dai.fakes.testnet`.

The auction contract will need to be registered as well, you could do this by sending it an arbitrary amount of \$DAI from the faucet or you can just register it since it doesn't need any FTs. You should also register the auctioneer,

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
near call dai.fakes.testnet storage_deposit '{"account_id": "<auctionContractId>"}' --useAccount <accountId> --deposit 0.1
```

Now you can go ahead and place a bid. DAI has 18 decimals meaning that 1 $DAI is made up of 10^24 smallest units. To make a bid of 2 $DAI you can use the command:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
near call dai.fakes.testnet ft_transfer_call '{"receiver_id": "<auctionContractId>", "amount": "2000000000000000000", "msg": ""}' --useAccount <bidderId> --depositYocto 1
```

## Auction architecture

When creating an application there are numerous ways to structure it. Here, we have one contract per auction meaning we have to deploy a new contract each time we want to host an auction. To make this easier we will leverage a factory contract to deploy auction contracts for an auctioneer. Deploying code for each auction gets expensive, with 100kb of storage costing 1 `$NEAR`, since each auction stores all the same type of information and implements the same methods one could instead decide to have multiple auctions per contract.

In such case, the Contract struct would be a map of auctions. We would implement a method to create a new auction by adding an entry to the map with the specific details of that individual auction.

<Tabs>
  <Tab title="🌐 JavaScript">
    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    class Contract {
        auctions: UnorderedMap<string, Auction>
    ```
  </Tab>

  <Tab title="🦀 Rust">
    ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
    pub struct Contract {
        auctions: IterableMap<String, Auction>
    ```
  </Tab>
</Tabs>

However, this architecture could be deemed less secure since if a bad actor were to gain access to the contract they would have access to every auction instead of just one.

***

## Conclusion

In this section, you learned a lot about fungible tokens: how to send and receive FTs in a smart contract, and then in sandbox tests how to deploy and initialize an FT contract, how to register a user in an FT contract, and send them some tokens, how to attach FTs to a smart contract call and finally how to view the FT balance of a user. With that, we now have our completed auction smart contract!

Taking a further step back we've taken a very simple auction contract and transformed it into a more production contract with thorough testing. To improve the auction we learned how to add a prize by introducing NFTs, and enabled auctioneers to host auctions with FTs.

In the [next part of the tutorial](./3.3-new-frontend), we're going to update the frontend to interact with the new features of the contract.
