Skip to content

Commit

Permalink
feat: offset fungible
Browse files Browse the repository at this point in the history
  • Loading branch information
CoviloMilos committed Feb 22, 2023
1 parent 465b667 commit 4a76353
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 17 deletions.
55 changes: 55 additions & 0 deletions src/abi/Registry_ABI.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,61 @@
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "vintage",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "requestRetireFungible",
"outputs": [
{
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "contract BaseERC20",
"name": "baseToken",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "maker",
"type": "address"
}
],
"name": "RetireFungibleRequested",
"type": "event"
}
]
}
73 changes: 68 additions & 5 deletions src/modules/offset.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { IRegistryContract, ProviderOrSigner, TheaNetwork } from "../types";
import { amountShouldBeGTZero, consts, ContractWrapper, signerRequired } from "../utils";
import { IBaseTokenManagerContract, IRegistryContract, ProviderOrSigner, RequestId, TheaNetwork } from "../types";
import { amountShouldBeGTZero, consts, ContractWrapper, Events, getAddress, signerRequired, TheaError } from "../utils";
import Registry_ABI from "../abi/Registry_ABI.json";
import { BigNumberish } from "@ethersproject/bignumber";
import { approve, checkBalance, execute } from "./shared";
import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
import { approve, checkBalance, execute, executeWithResponse, TheaERC20 } from "./shared";
import { Signer } from "@ethersproject/abstract-signer";
import { ContractReceipt } from "@ethersproject/contracts";
import { Contract, ContractReceipt, Event } from "@ethersproject/contracts";
import BaseTokenManager_ABI from "../abi/BaseTokenManager_ABI.json";

export class Offset extends ContractWrapper<IRegistryContract> {
readonly baseTokenManager: IBaseTokenManagerContract;
constructor(readonly providerOrSigner: ProviderOrSigner, readonly network: TheaNetwork) {
super(providerOrSigner, Registry_ABI, consts[`${network}`].registryContract);
this.baseTokenManager = new Contract(
consts[`${network}`].baseTokenManagerContract,
BaseTokenManager_ABI.abi,
providerOrSigner
) as IBaseTokenManagerContract;
}

/**
Expand All @@ -29,4 +36,60 @@ export class Offset extends ContractWrapper<IRegistryContract> {

return execute(this.contract.retire(tokenId, amount), { ...this.contractDetails, contractFunction: "retire" });
}

/**
* Stores a request to retire with NBT token of `amount`, locks the NBT tokens and emits event.
* Backend listens to event and process the request. Tokens are not transferred until backend calls `closeRetireFungible`
* function after processing and validating the recovery and retire of VCC is successful.
* @param vintage - vintage of NBT token
* @param amount - amount of NBT token to retire
* @returns RequestId & ContractReceipt {@link RequestId}
*/
async offsetFungible(vintage: number, amount: BigNumberish): Promise<ContractReceipt & RequestId> {
signerRequired(this.providerOrSigner);
amountShouldBeGTZero(amount);

const address = await this.getBaseTokenAddressByVintage(vintage);

const token = new TheaERC20(this.providerOrSigner, address);
const owner = await getAddress(this.providerOrSigner as Signer);

// Check balance
await token.checkERC20Balance(owner, amount);

// Approve
await token.approveERC20(owner, this.contractDetails.address, amount);

return executeWithResponse<RequestId>(
this.contract.requestRetireFungible(vintage, amount),
{
...this.contractDetails,
contractFunction: "requestRetireFungible"
},
this.extractRequestIdFromEvent
);
}

/**
* Callback function to extract request ID from the `UnwrapRequested` event
* @param events
* @returns {@link RequestId}
*/
extractRequestIdFromEvent(events?: Event[]): RequestId {
const response: RequestId = { requestId: undefined };
if (events) {
const event = events.find((event) => event.event === Events.retireOffset);
if (event) response.requestId = event.args?.requestId.toString();
}

return response;
}

private async getBaseTokenAddressByVintage(vintage: number): Promise<string> {
const address = await this.baseTokenManager.baseTokens(vintage);
if (BigNumber.from(address).isZero())
throw new TheaError({ type: "TOKEN_NOT_FOUND", message: `Token by ${vintage} vintage not found` });

return address;
}
}
14 changes: 7 additions & 7 deletions src/modules/unwrap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProviderOrSigner, IRegistryContract, UnwrapTokenState, UnwrapRequestId, TheaNetwork } from "../types";
import { ProviderOrSigner, IRegistryContract, UnwrapTokenState, RequestId, TheaNetwork } from "../types";
import { consts, ContractWrapper, Events, signerRequired, TheaError, tokenAmountShouldBeTon } from "../utils";
import Registry_ABI from "../abi/Registry_ABI.json";
import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
Expand All @@ -17,13 +17,13 @@ export class Unwrap extends ContractWrapper<IRegistryContract> {
* @param tokenId id of the VCC token
* @param amount amount of tokens to unwrap
* @param offchainAccount offchain account to transfer the tokens to
* @returns UnwrapRequestId&ContractReceipt {@link UnwrapRequestId}
* @returns RequestId & ContractReceipt {@link RequestId}
*/
async unwrapToken(
tokenId: BigNumberish,
amount: BigNumberish,
offchainAccount: string
): Promise<ContractReceipt & UnwrapRequestId> {
): Promise<ContractReceipt & RequestId> {
signerRequired(this.providerOrSigner);
tokenAmountShouldBeTon(amount);

Expand All @@ -34,7 +34,7 @@ export class Unwrap extends ContractWrapper<IRegistryContract> {
spender: this.contractDetails.address
});

return executeWithResponse<UnwrapRequestId>(
return executeWithResponse<RequestId>(
this.contract.unwrap(tokenId, amount, offchainAccount),
{
...this.contractDetails,
Expand Down Expand Up @@ -77,10 +77,10 @@ export class Unwrap extends ContractWrapper<IRegistryContract> {
/**
* Callback function to extract request ID from the `UnwrapRequested` event
* @param events
* @returns {@link UnwrapRequestId}
* @returns {@link RequestId}
*/
extractRequestIdFromEvent(events?: Event[]): UnwrapRequestId {
const response: UnwrapRequestId = { requestId: undefined };
extractRequestIdFromEvent(events?: Event[]): RequestId {
const response: RequestId = { requestId: undefined };
if (events) {
const event = events.find((event) => event.event === Events.unwrap);
if (event) response.requestId = event.args?.requestId.toString();
Expand Down
2 changes: 2 additions & 0 deletions src/types/IBaseTokenManagerContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ export interface IBaseTokenManagerContract extends Contract {
): Promise<ContractTransaction>;

baseCharacteristics(): Promise<BaseTokenCharactaristics>;

baseTokens(arg0: PromiseOrValue<BigNumberish>): Promise<string>;
}
2 changes: 1 addition & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export type SwapOptions = {
deadline?: number; // Unix timestamp
recipient?: string;
};
export type UnwrapRequestId = { requestId?: string };
export type RequestId = { requestId?: string };

export enum TokenizationStatus {
IN_QUEUE = "IN_QUEUE",
Expand Down
7 changes: 4 additions & 3 deletions src/utils/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export enum Events {
unwrap = "UnwrapRequested",
convert = "Converted",
recover = "Recovered",
rollTokens = "Rolled"
rollTokens = "Rolled",
retireOffset = "RetireFungibleRequested"
}

export type EnvConfig = {
Expand All @@ -73,13 +74,13 @@ export type EnvConfig = {
export const consts: { [key in TheaNetwork]: EnvConfig } = {
[TheaNetwork.GANACHE]: {
networkName: "GANACHE",
registryContract: "0xe135783649BfA7c9c4c6F8E528C7f56166efC8a6",
registryContract: "0x686AfD6e502A81D2e77f2e038A23C0dEf4949A20",
theaERC1155Contract: "0x2E1f232a9439C3D459FcEca0BeEf13acc8259Dd8",
vintageTokenContract: "0x686AfD6e502A81D2e77f2e038A23C0dEf4949A20",
sdgTokenContract: "0x43D1F9096674B5722D359B6402381816d5B22F28",
ratingTokenContract: "0x4261D524bc701dA4AC49339e5F8b299977045eA5",
currentNbtTokenContract: "", // Call setCurrentNBTContractAddress to set address at init/thea.ts
baseTokenManagerContract: "0xE100c4ffFF7c00253BA4A2a695F5ac909d756D76",
baseTokenManagerContract: "0x95C8f889701f20b624875a5188bEbDc9289b4F51",
baseTokenManagerDeployerContract: "0x3ace09bba3b8507681146252d3dd33cd4e2d4f63",
stableTokenContract: "0x6B175474E89094C44Da98b954EedeAC495271d0F", //DAI
quoterContract: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
Expand Down
3 changes: 2 additions & 1 deletion src/utils/theaError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export type ErrorType =
| "INVALID_CHUNK_SIZE"
| "SIGNER_REQUIRES_PROVIDER"
| "MISSING_CURRENT_NBT_CONTRACT_ADDRESSS"
| "SUBGRAPH_CALL_ERROR";
| "SUBGRAPH_CALL_ERROR"
| "TOKEN_NOT_FOUND";

export type ErrorProps = {
type: ErrorType;
Expand Down

0 comments on commit 4a76353

Please sign in to comment.