Comment on page
Getting Started
The page describes the steps for protocols to integrate with Ferum.
This page hasn't been updated yet and might be out of date.
Ferum is currently deployed on testnet to
0x09c94d95f00a30b11aa18052c0276ff890d6ae754d5214cc85c714fa5b7c4133
- 1.First, you need to get the latest Ferum module address from the Ferum Contract. This will be used to call entry functions and reference all test coins.
- 2.Create an account, fund it with Aptos coins through the faucet, and mint some test USDF coins for testing purposes — see Creating Your First Order to get started.
- 3.Decide if you want to integrate with Ferum through a Smart Contract (i.e. Move Module) or through the Aptos SDK (i.e. TypeScript).
- 1.
- 2.
- 4.Optionally, to create a new market, talk to the Ferum team. They will need to manually call
init_market_entry
to allow trading brand-new coin pairs. Ferum will allow permissionless market creation soon. - 5.
- 6.
- 7.
- 8.
To integrate Ferum into your Aptos contract, you will need to include Ferum as a move dependency to your
Move.toml
file like below:[dependencies]
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "testnet" }
Ferum = { git = "https://github.com/ferum-dex/ferum.git", rev = "testnet", subdir = "contract" }
Move caches modules so you might run into errors if the upstream module is updated but the cache version is stale. To fix this run
aptos move clean
.Ferum will release an SDK in many popular languages as a part of Milestone Beta. In the meantime, the Ferum contract can be called through Aptos SDKs. An example Ferum contract call using the TypeScript SDK is shown below (
sdk version = 1.3.13
):1
import {
2
AptosAccount,
3
AptosClient,
4
TxnBuilderTypes,
5
} from "aptos";
6
7
// Update to the latest by checking Ferum's Move.toml file:
8
// https://github.com/ferum-dex/ferum/blob/testnet/contract/Move.toml
9
const FERUM = "0x7e9d4ebb1ac454c759719fc87b7f13b116d2f226c76d838970bf80e6aaea9000";
10
const NODE_URL = "https://fullnode.devnet.aptoslabs.com/v1";
11
const Client = new AptosClient(NODE_URL);
12
13
// Shown for illustration purposes only. You should probably be reading this
14
// from the environment variable or a secret store in a production setting.
15
const PRIVATE_KEY = "<ACCOUNT_PRIVATE_KEY>";
16
const Account = account = new AptosAccount(Uint8Array.from(Buffer.from(PRIVATE_KEY)));
17
18
// Helper function to send signed transactions.
19
export async function sendSignedTransactionWithAccount(
20
signerAccount: AptosAccount,
21
entryFunction: TxnBuilderTypes.EntryFunction,
22
) {
23
const entryFunctionPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(entryFunction);
24
25
// Ge the latest sequence number and chain id.
26
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
27
client.getAccount(signerAccount.address()),
28
client.getChainId(),
29
]);
30
31
const rawTxn = new TxnBuilderTypes.RawTransaction(
32
// Transaction sender account address
33
TxnBuilderTypes.AccountAddress.fromHex(signerAccount.address()),
34
BigInt(sequenceNumber),
35
entryFunctionPayload,
36
// Max gas unit to spend
37
BigInt(2000),
38
// Gas price per unit
39
BigInt(100),
40
// Expiration timestamp. The transaction is discarded if it is not
41
// executed within 10 seconds from now.
42
BigInt(Math.floor(Date.now() / 1000) + 10),
43
new TxnBuilderTypes.ChainId(chainId),
44
);
45
const signedTxn = await client.signTransaction(signerAccount, rawTxn);
46
const pendingTxn = await client.submitSignedBCSTransaction(signedTxn);
47
return pendingTxn.hash;
48
}
49
50
// Helper function to create limit order.
51
async function addOrder(
52
signerAccount: AptosAccount,
53
instrumentCoin: string,
54
quoteCoin: string,
55
side: 'buy' | 'sell',
56
typ: 'resting' | 'post' | 'ioc' | 'fok',
57
price: number,
58
quantity: number,
59
) {
60
let parsedTyp = 0;
61
if (typ === 'resting') {
62
parsedTyp = 1;
63
} else if (typ === 'post') {
64
parsedTyp = 2;
65
} else if (typ === 'ioc') {
66
parsedTyp = 3;
67
} else if (typ === 'fok') {
68
parsedTyp = 4;
69
}
70
const entryFunction = TxnBuilderTypes.EntryFunction.natural(
71
`${FERUM}::market`,
72
"add_order_entry",
73
coinTypeTags(instrumentCoin, quoteCoin),
74
[
75
BCS.bcsSerializeU8(side === 'buy' ? 2 : 1), // Side
76
BCS.bcsSerializeU8(parsedTyp), // Type
77
BCS.bcsSerializeUint64(price), // Price
78
BCS.bcsSerializeUint64(quantity), // Quantity
79
BCS.bcsSerializeStr(""), // ClientOrderID
80
]
81
);
82
return await sendSignedTransactionWithAccount(signerAccount, entryFunction);
83
}
84
85
async function main() {
86
// Places a standard limit SELL for 1 APT with a limit price of 1 USDF.
87
88
const price = "1000";
89
const quantity = "1000";
90
const side = "sell";
91
const typ = "resting";
92
const quoteCoinType = `${FERUM}::test_coins::USDF`;
93
const instrumentCoinType = "0x1::aptos_coin::AptosCoin";
94
95
const txHash = await addOrder(account, instrumentCoinType, quoteCoinType, side, typ, price, quantity)
96
const txResult = await client.waitForTransactionWithResult(txHash);
97
console.log(txResult);
98
}
99
100
main();