Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FA2 support #1

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions .github/workflows/edonet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: [ dev ]

jobs:
test-unit:
test-unit-FA12:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -24,7 +24,24 @@ jobs:
with:
time: '30s'
- run: yarn run test ./test/unit/**/*
test-integration:
test-unit-FA2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- run: yarn
- run: yarn run fix-ligo-version 0.11.0
- run: yarn run sandbox:start &
- name: Wait 30 seconds for sandbox
uses: kibertoad/wait-action@master
with:
time: '30s'
- run: yarn run test ./test/unit/**/* --token FA2
test-integration-FA12:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 3 additions & 0 deletions contracts/main/farm/farmFA2.religo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#define TOKEN_FA2

#include "farm.religo"
990 changes: 990 additions & 0 deletions contracts/main/farm/test/tokenTzip12-FA2.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions contracts/partials/farm/claim/claim.religo
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ let claim = ((storage): (storage)): entrypointReturn => {
storage.addresses.rewardReserve, // from
delegator, // to
delegatorReward, // value
#if TOKEN_FA2
storage.tokenIds.reward, // tokenId
#endif
storage.addresses.rewardTokenContract // tzip7 contract's address
);

Expand Down
3 changes: 3 additions & 0 deletions contracts/partials/farm/deposit/deposit.religo
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ let deposit = ((depositParameter, storage): (depositParameter, storage)): entryp
delegator, // from
Tezos.self_address, // to
depositParameter, // value
#if TOKEN_FA2
storage.tokenIds.lp, // tokenId
#endif
storage.addresses.lpTokenContract // tzip7 contract's address
);

Expand Down
3 changes: 3 additions & 0 deletions contracts/partials/farm/escape/escape.religo
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ let escape = ((escapeParameter, storage): (escapeParameter, storage)): entrypoin
Tezos.self_address, // from
delegator, // to
delegatorRecord.lpTokenBalance, // value
#if TOKEN_FA2
storage.tokenIds.lp, // tokenId
#endif
storage.addresses.lpTokenContract
);

Expand Down
33 changes: 33 additions & 0 deletions contracts/partials/farm/helpers/transfer.religo
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
#if TOKEN_FA2
/**
* This adapter is used to interact with TZIP-12 (FA2) token contracts.
*/
let transfer = ((from_, to_, value, tokenId, tokenContractAddress): (address, address, nat, nat, address)): operation => {
let transferContents: transferContents = {
to_: to_,
token_id: tokenId,
amount: value
};

let transfer = {
from_: from_,
txs: [transferContents]
};

let transferParameter: transferParameter = [transfer];

let tokenContract: option(contract(transferParameter)) = Tezos.get_entrypoint_opt("%transfer", tokenContractAddress);
let tokenContract: contract(transferParameter) = switch (tokenContract) {
| Some(contract) => contract
| None => (failwith(errorNoContractFound): contract(transferParameter))
};

let operation = Tezos.transaction(
transferParameter,
0tez,
tokenContract
);
operation;
};
#else
/**
* This adapter is used to interact with TZIP-7 (FA1.2) token contracts.
*/
Expand All @@ -20,3 +52,4 @@ let transfer = ((from_, to_, value, tokenContractAddress): (address, address, na
);
operation;
};
#endif
5 changes: 4 additions & 1 deletion contracts/partials/farm/storage/storage.religo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ type storage = {
farm: farm,
delegators: big_map(delegator, delegatorRecord),
farmLpTokenBalance: nat,
addresses: addresses
addresses: addresses,
#if TOKEN_FA2
tokenIds: tokenIds,
#endif
};

#include "delegatorsRepository.religo"
Expand Down
29 changes: 28 additions & 1 deletion contracts/partials/farm/storage/types.religo
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,32 @@ type getBalanceParameter =

type getBalanceResponse = nat;

#if TOKEN_FA2
type transferContents =
[@layout:comb]
{
to_: address,
token_id: nat,
amount: nat
};

type transfer =
[@layout:comb]
{
from_: address,
txs: list(transferContents)
};

type transferParameter = list(transfer);
#else
type transferParameter =
[@layout:comb]
{
[@annot:from] from_: address,
[@annot:to] to_: address,
value: nat,
};
#endif

type updatePoolAction = Skip | UpdateBlock | UpdateRewards;

Expand All @@ -44,5 +63,13 @@ type addresses = {
admin: address,
lpTokenContract: address,
rewardTokenContract: address,
rewardReserve: address
rewardReserve: address,
};

#if TOKEN_FA2
type tokenId = nat;
type tokenIds = {
lp: tokenId,
reward: tokenId,
};
#endif
3 changes: 3 additions & 0 deletions contracts/partials/farm/withdraw/withdraw.religo
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ let withdraw = ((withdrawParameter, storage): (withdrawParameter, storage)): ent
Tezos.self_address, // from
delegator, // to
withdrawParameter, // value
#if TOKEN_FA2
storage.tokenIds.lp, // tokenId
#endif
storage.addresses.lpTokenContract
);

Expand Down
23 changes: 23 additions & 0 deletions migrations/initialStorage/tokenFA2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MichelsonMap, UnitValue } from "@taquito/taquito";
import accounts from "../../scripts/sandbox/accounts";
import decimals from '../../decimals-config.json';
import BigNumber from 'bignumber.js';
const initialStorage = {};

initialStorage.base = () => ({
tzip12: {
tokensLedger: new MichelsonMap,
tokenOperators: new MichelsonMap,
u: UnitValue
},
u: UnitValue
});

initialStorage.withBalances = () => {
const storage = initialStorage.base();
storage.tzip12.tokensLedger.set({ 0: accounts.walter.pkh, 1: 0 }, (new BigNumber(1000).multipliedBy(decimals.rewardToken)).toFixed());

return storage
};

export default initialStorage;
12 changes: 10 additions & 2 deletions test/helpers/farm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@ import { TezosToolkit, UnitValue } from "@taquito/taquito";
import BigNumber from "bignumber.js";
import accounts from "../../scripts/sandbox/accounts";
import { contractStorage, delegatorRecord } from "./types";
import tokenStandard from "./tokenStandard";

const farm = artifacts.require('farm');
let farm;

switch (tokenStandard) {
case "FA12":
farm = artifacts.require('farm');
break;
case "FA2":
farm = artifacts.require('farmFA2');
break;
}

const testHelpers = (instance, Tezos) => {
return {
Expand Down Expand Up @@ -106,7 +115,6 @@ export default {
signer: await InMemorySigner.fromSecretKey(accounts.alice.sk)
});


const instance = await Tezos.contract.at(address);

return testHelpers(instance, Tezos);
Expand Down
83 changes: 83 additions & 0 deletions test/helpers/tokenFA2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { InMemorySigner } from "@taquito/signer";
import { TezosToolkit } from "@taquito/taquito";
import BigNumber from 'bignumber.js';

import accounts from "../../scripts/sandbox/accounts";
import tokenFA2ContractMichelson from "../../contracts/main/farm/test/tokenTzip12-FA2.json"
import decimals from '../../decimals-config.json';
import _initialStorage from '../../migrations/initialStorage/tokenFA2';

export const tokenId = 0;

const tzip12Helpers = (instance, Tezos) => {
return {
instance: instance,
Tezos: Tezos,
transfer: async function(transferParameters) {
const operation = await instance.methods.transfer([{
from_: transferParameters.from,
txs: [{
to_: transferParameters.to,
token_id: tokenId,
amount: transferParameters.value
}]
}]).send();

await operation.confirmation(1);
return operation
},
add_operator: async function(owner, spender) {
const operation = await instance.methods.update_operators(
[{
'add_operator': {
owner: owner,
operator: spender
}
}]
).send();
await operation.confirmation(1);
return operation
},
getStorage: async function() {
return await instance.storage();
},
getBalance: async function(address): Promise<BigNumber> {
const balance = await (await this.getStorage())
.tzip12
.tokensLedger
.get(
{ 0: address, 1: tokenId }
) || new BigNumber(0);
return balance;
},

}
}

export function rewardToken(value): string {
return (new BigNumber(value)).multipliedBy(new BigNumber(decimals.rewardToken)).toFixed();
}

export function lpToken(value): string {
return (new BigNumber(value)).multipliedBy(new BigNumber(decimals.lpToken)).toFixed();
}

export default {
originate: async function(contract?: string) {

const Tezos = new TezosToolkit(tezos._rpcClient.url);
Tezos.setProvider({
signer: await InMemorySigner.fromSecretKey(accounts.alice.sk)
});

const operation = await Tezos.contract
.originate({
code: tokenFA2ContractMichelson,
storage: _initialStorage.withBalances(),
});
console.log(contract + ' Token contract originated at', operation.contractAddress);
const instance = await operation.contract();

return tzip12Helpers(instance, Tezos)
}
};
7 changes: 7 additions & 0 deletions test/helpers/tokenStandard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// indexOf returns -1 if value is not present
const tokenArgvIndex = process.argv.indexOf('--token');
const tokenArgv = process.argv[tokenArgvIndex + 1];
const defaultStandard = 'FA12';
const tokenStandard: string = (tokenArgvIndex == -1) ? defaultStandard : tokenArgv;

export default tokenStandard;
34 changes: 26 additions & 8 deletions test/unit/claim/before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,43 @@ import _taquito from '../../helpers/taquito';
import _farmContract from '../../helpers/farm';
import _initialStorage from "../../../migrations/initialStorage/farm";
import accounts from '../../../scripts/sandbox/accounts';
import tokenStandard from '../../helpers/tokenStandard';
import { tokenId } from '../../helpers/tokenFA2';

export async function prepareFarm(delegators, rewardPerBlock, rewardTokenContract, farmContract){

const startingBlockLevel = await _taquito.getCurrentBlockLevel();

farmContract = await _farmContract.originate(
_initialStorage.test.claim(
rewardTokenContract.instance.address,
delegators,
rewardPerBlock,
startingBlockLevel
)
const initialStorage = _initialStorage.test.claim(
rewardTokenContract.instance.address,
delegators,
rewardPerBlock,
startingBlockLevel
);

if (tokenStandard == "FA2") {
initialStorage.tokenIds = {
lp: tokenId,
reward: tokenId
};
}

farmContract = await _farmContract.originate(initialStorage);

// give allowance to farm contract to spend on behalf of the address that owns reward tokens
await _taquito.signAs(accounts.walter.sk, rewardTokenContract, async () => {
const owner = accounts.walter.pkh;
const spender = farmContract.instance.address;
const value = rewardToken('800');
await rewardTokenContract.approve(spender, value);

switch (tokenStandard) {
case "FA12":
await rewardTokenContract.approve(spender, value);
break;
case "FA2":
await rewardTokenContract.add_operator(owner, spender);
break;
}
});

return farmContract;
Expand Down
Loading