Request form
Ajna V2
  • Liquidity
  • Borrowing
  • Lending
  • Lending
  • Protocol
  • Audited
Docs
Source
ChefGPT

Ajna is a peer to peer, oracleless, permissionless lending protocol with no governance, accepting both fungible and non fungible tokens as collateral

base64.sol
Clone.sol
ClonesWithImmutableArgs.sol
IERC1271.sol
ReentrancyGuard.sol
ERC20.sol
draft-IERC20Permit.sol
IERC20Metadata.sol
IERC20.sol
SafeERC20.sol
ERC721.sol
IERC721Metadata.sol
IERC721.sol
IERC721Receiver.sol
Address.sol
Context.sol
ECDSA.sol
SignatureChecker.sol
ERC165.sol
IERC165.sol
Math.sol
SafeCast.sol
Multicall.sol
Strings.sol
EnumerableSet.sol
PRBMath.sol
PRBMathSD59x18.sol
PRBMathUD60x18.sol
FlashloanablePool.sol
PermitERC721.sol
Pool.sol
PoolDeployer.sol
ERC20Pool.sol
ERC20PoolFactory.sol
ERC721Pool.sol
ERC721PoolFactory.sol
IPoolBorrowerActions.sol
IPoolDerivedState.sol
IPoolErrors.sol
IPoolEvents.sol
IPoolImmutables.sol
IPoolInternals.sol
IPoolKickerActions.sol
IPoolLenderActions.sol
IPoolLPActions.sol
IPoolSettlerActions.sol
IPoolState.sol
IPoolTakerActions.sol
IERC20Pool.sol
IERC20PoolBorrowerActions.sol
IERC20PoolEvents.sol
IERC20PoolFactory.sol
IERC20PoolImmutables.sol
IERC20PoolLenderActions.sol
IERC20Taker.sol
IERC721Pool.sol
IERC721PoolBorrowerActions.sol
IERC721PoolErrors.sol
IERC721PoolEvents.sol
IERC721PoolFactory.sol
IERC721PoolImmutables.sol
IERC721PoolLenderActions.sol
IERC721PoolState.sol
IERC721Taker.sol
IERC3156FlashBorrower.sol
IERC3156FlashLender.sol
IPool.sol
IPoolFactory.sol
IPositionManager.sol
IPositionManagerDerivedState.sol
IPositionManagerErrors.sol
IPositionManagerEvents.sol
IPositionManagerOwnerActions.sol
IPositionManagerState.sol
BorrowerActions.sol
KickerActions.sol
LenderActions.sol
LPActions.sol
PoolCommons.sol
PositionNFTSVG.sol
SettlerActions.sol
TakerActions.sol
PoolHelper.sol
RevertsHelper.sol
SafeTokenNamer.sol
Buckets.sol
Deposits.sol
Loans.sol
Maths.sol
PoolInfoUtils.sol
PoolInfoUtilsMulticall.sol
PositionManager.sol

TVL

$.NaK

6 downloads

Chains

Authors

Ajna V2
  • Liquidity
  • Borrowing
  • Lending
  • Lending
  • Protocol
  • Audited
Info
Source
ChefGPT
Expand
Share

Get Cookin'

6 downloads

Chains

Authors

Ajna contracts

The Ajna protocol is a non-custodial, peer-to-peer, permissionless lending, borrowing and trading system that requires no governance or external price feeds to function. The protocol consists of pools: pairings of quote tokens provided by lenders and collateral tokens provided by borrowers. Ajna is capable of accepting fungible tokens as quote tokens and both fungible and non-fungible tokens as collateral tokens.

Accepted tokens:

Caveats:

Token limitations

  • The following types of tokens are incompatible with Ajna, and no countermeasures exist to explicitly prevent creating a pool with such tokens, actors should use them at their own risk:
    • NFT and fungible tokens which charge a fee on transfer.
    • Fungible tokens whose balance rebases.
  • The following types of tokens are incompatible with Ajna, and countermeasures exist to explicitly prevent creating a pool with such tokens:
    • Fungible tokens with more than 18 decimals or 0 decimals, whose decimals() function does not return a constant value, or which do not implement the optional decimals() function.

Pool limitations

  • Borrowers cannot draw debt from a pool in the same block as when the pool was created.
  • With the exception of quantized prices, pool inputs and most accumulators are not explicitly limited. The pool will stop functioning when the bounds of a uint256 need to be exceeded to process a request.

Position NFT limitations

  • Position NFTs are vulnerable to front running attacks when buying from open markets. Seller of such NFT could redeem positions before transfer, and then transfer an NFT without any value to the buyer. Ajna positions NFTs should not be purchased from open markets.

Development

Requirements

  • python 3.0+
  • eth-brownie 1.18.1+
  • ganache 7.0+ is required.
  • foundry aka forge 0.2.0+ is required.

Foundry setup

curl -L https://foundry.paradigm.xyz | bash
  • To get the latest forge binaries, run:
foundryup

Brownie setup

Brownie with Ganache

  • Install Ganache
npm i -g ganache

Brownie with Hardhat

  • Install Hardhat
npm install --save-dev hardhat
  • To use hardhat instead of ganache, add --network hardhat-fork to override the configured network

Caveats:

  • Brownie does not support mining empty blocks using chain.mine
  • Brownie does not report custom errors raised by the contract when using Hardhat

Project Setup

  • Make a copy of .env.example and name it .env. Add the values for
    • ETHERSCAN_TOKEN - required by brownie to verify contract sources
    • WEB3_INFURA_PROJECT_ID - required by brownie to fork chain
    • ETH_RPC_URL - required by forge to fork chain
  • run
make all

Implementation notes

Pool external calls carry the nonReentrant modifier to prevent invocation from flashLoan and take callbacks.

Documentation

Documentation can be generated as mdbook from Solidity NatSpecs by using forge doc command. For example, to generate documentation and serve it locally on port 4000 (http://localhost:4000/):

forge doc --serve --port 4000

Tests

Forge tests

  • run tests without the gas load tests (good for checking validity)
make test
  • run tests with gas report, used for gas comparison of changes:
make test-with-gas-report
  • run load tests with gas report, used for gas comparison of changes (takes longer to execute):
make test-load

Brownie tests

  • run integration tests:
brownie test
  • to view stdout on long-running tests, use brownie test -s.

Debugging Brownie integration tests

  • to drop into the console upon test failure:
brownie test --interactive
  • From there, you can pull the last transaction using tx=history[-1], followed by tx.events to debug.

Contract size

To display contract code sizes run:

forge build --sizes

or

brownie compile --size

Code Coverage

  • generate basic code coverage report:
make coverage
  • exclude tests from code coverage report:
apt-get install lcov
bash ./check-code-coverage.sh

Slither Analyzer

  • Install Slither
pip install slither-analyzer
  • Make sure the default solc version is set to the same version as contracts (currently 0.8.18). This can be done by installing and using solc-select:
pip install solc-select && solc-select install 0.8.18 && solc-select use 0.8.18
  • Run analyze
make analyze

Licensing

For purposes of the Business Service License: (i) the term “Licensor” means Ajna Labs, LLC, (ii) the term Licensed Work means Licensor’s proprietary software marketed under the name The Ajna Protocol™ and useful for purposes of facilitating the lending and borrowing of digital assets, (iii) the term “Additional Use Grants” means a grant of rights in the Licensed Work that are not included in the Business Service License and are granted by Licensor pursuant to a separate agreement between Licensor and one or more third parties, and (iv) the term “Change Date” means April 1, 2026 or such other date as Licensor may specify on or before April 1, 2026.

The licensed work is under the Business Service License ("BUSL license") with but not limited to the following exceptions:

  • To facilitate integrations, public-facing interfaces are licensed under MIT, as indicated in their SPDX headers.
  • As a derivative work of ds-math, Maths.sol is licensed under GPL-3.0-or-later, as indicated in its SPDX header.
  • As a derivative work of SafeERC20Namer, SafeTokenNamer.sol is licensed under GPL-3.0-or-later, as indicated in its SPDX header.
  • Unit and integration tests under tests folder remain unlicensed, unless their file header specifies otherwise.

Prior to the Change Date, Licensor intends to transfer ownership of the Licensed Work to a to-be-organized not-for-profit foundation or similar public benefit focused entity (the “Ajna Foundation”), whereupon the rights, duties and obligations of Licensor under the BUSL License shall, without further act or deed of the parties, be assigned to Ajna Foundation, which entity shall thereafter be, and assume all rights, duties and obligations of (but not the liabilities, if any, of), the Licensor under the Business Service License.

Licensor reserves the right to specify Additional Use Grants at their discretion and to facilitate changes enacted by the Grant Coordination process, provided always that Additional Use Grants shall not conflict with the Business License. Licensor grants third parties permission to deploy The Ajna Protocol to other public blockchains and scaling solutions, hereby referred to as the "target chain", so long as:

  • No other functional and successful deployment of Ajna is available on the target chain.
  • No modification to Solidity source files in the protocol is made, and no changes are made which conflict with the Business License.
  • Prior to deployment, the canonical burn-wrapped AJNA token (bwAJNA) on Ethereum mainnet is bridged to the target chain.
  • Upon deployment, the protocol is configured to use the bwAJNA token on the target chain.

Prior to the Change Date, Licensor shall elect the Change License governing the Licensed Work after the Change Date, which license shall be an Open Source Initiative compliant license, provided always that the Change License shall be GPL Version 2.0 compatible. Once elected, Licensor may change its Change License designation at any time on or before the Change Date by updating this file in the master branch of source control.

Modifications to, or notices of actions by Licensor, contemplated above or under the Business Service License shall be communicated by updating this file in the master branch of source control. All such updates are binding on Licensor and all licensees under the Business Service License upon the publication of the relevant update.

Deployment

A deployment script has been created to automate deployment of libraries, factory contracts, and manager contracts.

To use it, ensure the following env variables are in your .env file or exported into your environment.

Environment VariablePurpose
AJNA_TOKENaddress of the AJNA token on your target chain
DEPLOY_ADDRESSaddress from which you wish to deploy
DEPLOY_KEYpath to the JSON keystore file for the deployment address
ETHERSCAN_API_KEYrequired to verify contracts
ETH_RPC_URLnode on your target deployment network

To run:

make deploy-contracts

Upon completion, contract addresses will be printed to stdout:

== Logs ==
  Deploying to chain with AJNA token address 0xaadebCF61AA7Da0573b524DE57c67aDa797D46c5
  === Deployment addresses ===
  ERC20PoolFactory       0x14F2474fB5ea9DF82059053c4F85A8C803Ab10C9
  ERC721PoolFactory      0xb0d1c875B240EE9f6C2c3284a31b10f1EC6De7d2
  PoolInfoUtils          0x08F304cBeA7FAF48C93C27ae1305E220913a571d
  PoolInfoUtilsMulticall 0x12874db433dBF1D0f3c73B39F96B009093A56E0E
  PositionManager        0xC4114D90F51960854ab574297Cf7CC131d445F29

Record these addresses. If Etherscan verification fails on the first try, copy the deployment command from the Makefile, and tack a --resume switch onto the end. Failing that, manual verification is possible. Following steps show how to do this on Goerli (chainId 5), using addresses from the example output above.

  • Open broadcast/5/run-latest.json and find the "libraries" section towards the end of the file.
  • Copy/paste the libraries config into the [profile.default] section of foundry.toml, replacing the : with an =.
  • Run the following commands, adjusting addresses as appropriate. PoolInfoUtilsMulticall constructor takes the address of PoolInfoUtils. PositionManager constructor takes the factory addresses.
    forge verify-contract --chain-id 5 --watch 0x14F2474fB5ea9DF82059053c4F85A8C803Ab10C9 ERC20PoolFactory --constructor-args $(cast abi-encode "constructor(address)" ${AJNA_TOKEN})
    forge verify-contract --chain-id 5 --watch 0xb0d1c875B240EE9f6C2c3284a31b10f1EC6De7d2 ERC721PoolFactory --constructor-args $(cast abi-encode "constructor(address)" ${AJNA_TOKEN})
    forge verify-contract --chain-id 5 --watch 0x08F304cBeA7FAF48C93C27ae1305E220913a571d PoolInfoUtils
    forge verify-contract --chain-id 5 --watch 0x12874db433dBF1D0f3c73B39F96B009093A56E0E PoolInfoUtilsMulticall --constructor-args $(cast abi-encode "constructor(address)" 0x08F304cBeA7FAF48C93C27ae1305E220913a571d)
    forge verify-contract --chain-id 5 --watch 0xC4114D90F51960854ab574297Cf7CC131d445F29 PositionManager --constructor-args $(cast abi-encode "constructor(address,address)" 0x14F2474fB5ea9DF82059053c4F85A8C803Ab10C9 0xb0d1c875B240EE9f6C2c3284a31b10f1EC6De7d2)
    
  • To verify pool contracts, return to the run-latest.json file and search for the factory contracts. After the factory bytecode, under the additionalContracts section should be a CREATE action. Copy the address for the "seed" pool from each factory deployment, and verify this seed pool.
    forge verify-contract --chain-id 5 --watch 0x5a4fB4f6a83282D62c3fc87c4DFE9A2849D987E9 ERC20Pool
    forge verify-contract --chain-id 5 --watch 0x7c79C719081d987678b1cFAb5f95B48f3CEC55b2 ERC721Pool
    

Validation

Validate the deployment by creating a pool. Set relevant environment variables, and run the following:

cast send ${AJNA_ERC20_POOLFACTORY} "deployPool(address,address,uint256)(address)" \
	${WBTC_TOKEN} ${DAI_TOKEN} 50000000000000000 \
	--from ${DEPLOY_ADDRESS} --keystore ${DEPLOY_KEY}

Where did it deploy the pool? Let's find out:

export ERC20_NON_SUBSET_HASH=0x2263c4378b4920f0bef611a3ff22c506afa4745b3319c50b6d704a874990b8b2
cast call ${AJNA_ERC20_POOLFACTORY} "deployedPools(bytes32,address,address)(address)" \
	${ERC20_NON_SUBSET_HASH} ${WBTC_TOKEN} ${DAI_TOKEN}

Record the pool address.

Run an approval to let the contract spend some of your quote token, and then add some liquidity:

cast send ${DAI_TOKEN} "approve(address,uint256)" ${WBTC_DAI_POOL} 50000ether \
	--from ${DEPLOY_ADDRESS} --keystore ${DEPLOY_KEY}
cast send ${WBTC_DAI_POOL} "addQuoteToken(uint256,uint256,uint256)" 100ether 3232 $(($(cast block -f timestamp) + 60)) \
	--from ${DEPLOY_ADDRESS} --keystore ${DEPLOY_KEY}
Ajna is a peer to peer, oracleless, permissionless lending protocol with no governance, accepting both fungible and non fungible tokens as collateral
base64.sol
Clone.sol
ClonesWithImmutableArgs.sol
IERC1271.sol
ReentrancyGuard.sol
ERC20.sol
draft-IERC20Permit.sol
IERC20Metadata.sol
IERC20.sol
SafeERC20.sol
ERC721.sol
IERC721Metadata.sol
IERC721.sol
IERC721Receiver.sol
Address.sol
Context.sol
ECDSA.sol
SignatureChecker.sol
ERC165.sol
IERC165.sol
Math.sol
SafeCast.sol
Multicall.sol
Strings.sol
EnumerableSet.sol
PRBMath.sol
PRBMathSD59x18.sol
PRBMathUD60x18.sol
FlashloanablePool.sol
PermitERC721.sol
Pool.sol
PoolDeployer.sol
ERC20Pool.sol
ERC20PoolFactory.sol
ERC721Pool.sol
ERC721PoolFactory.sol
IPoolBorrowerActions.sol
IPoolDerivedState.sol
IPoolErrors.sol
IPoolEvents.sol
IPoolImmutables.sol
IPoolInternals.sol
IPoolKickerActions.sol
IPoolLenderActions.sol
IPoolLPActions.sol
IPoolSettlerActions.sol
IPoolState.sol
IPoolTakerActions.sol
IERC20Pool.sol
IERC20PoolBorrowerActions.sol
IERC20PoolEvents.sol
IERC20PoolFactory.sol
IERC20PoolImmutables.sol
IERC20PoolLenderActions.sol
IERC20Taker.sol
IERC721Pool.sol
IERC721PoolBorrowerActions.sol
IERC721PoolErrors.sol
IERC721PoolEvents.sol
IERC721PoolFactory.sol
IERC721PoolImmutables.sol
IERC721PoolLenderActions.sol
IERC721PoolState.sol
IERC721Taker.sol
IERC3156FlashBorrower.sol
IERC3156FlashLender.sol
IPool.sol
IPoolFactory.sol
IPositionManager.sol
IPositionManagerDerivedState.sol
IPositionManagerErrors.sol
IPositionManagerEvents.sol
IPositionManagerOwnerActions.sol
IPositionManagerState.sol
BorrowerActions.sol
KickerActions.sol
LenderActions.sol
LPActions.sol
PoolCommons.sol
PositionNFTSVG.sol
SettlerActions.sol
TakerActions.sol
PoolHelper.sol
RevertsHelper.sol
SafeTokenNamer.sol
Buckets.sol
Deposits.sol
Loans.sol
Maths.sol
PoolInfoUtils.sol
PoolInfoUtilsMulticall.sol
PositionManager.sol