Skip to content

Commit

Permalink
feature (dynamic sbts): added base implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
H34D committed Nov 7, 2023
1 parent ece42f7 commit 7c9c6a2
Show file tree
Hide file tree
Showing 18 changed files with 597 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/contracts/contract-modules/masa-module-base.ts
Expand Up @@ -220,7 +220,7 @@ export abstract class MasaModuleBase extends MasaBase {
| SoulLinker,
domain: TypedDataDomain,
types: Record<string, Array<TypedDataField>>,
value: Record<string, string | BigNumber | number>,
value: Record<string, string | BigNumber | number | boolean>,
signature: string,
authorityAddress: string,
) => {
Expand Down
20 changes: 10 additions & 10 deletions src/contracts/contract-modules/sbt/SSSBT/sssbt-contract-wrapper.ts
Expand Up @@ -16,6 +16,14 @@ import { SBTContractWrapper } from "../SBT/sbt-contract-wrapper";
export class SSSBTContractWrapper<
Contract extends ReferenceSBTSelfSovereign,
> extends SBTContractWrapper<Contract> {
public readonly types = {
Mint: [
{ name: "to", type: "address" },
{ name: "authorityAddress", type: "address" },
{ name: "signatureDate", type: "uint256" },
],
};

/**
* Signs an SBT based on its address
* @param name
Expand Down Expand Up @@ -63,7 +71,7 @@ export class SSSBTContractWrapper<
* @param authorityAddress
* @param slippage
*/
public prepareMint = async (
protected prepareMint = async (
paymentMethod: PaymentMethod,
name: string,
types: Record<string, Array<TypedDataField>>,
Expand Down Expand Up @@ -145,14 +153,6 @@ export class SSSBTContractWrapper<
}
}

const types = {
Mint: [
{ name: "to", type: "address" },
{ name: "authorityAddress", type: "address" },
{ name: "signatureDate", type: "uint256" },
],
};

// fill the collection with data
const value: {
to: string;
Expand All @@ -167,7 +167,7 @@ export class SSSBTContractWrapper<
const { price, paymentAddress } = await this.prepareMint(
paymentMethod,
"ReferenceSBTSelfSovereign",
types,
this.types,
value,
signature,
authorityAddress,
Expand Down
@@ -0,0 +1,298 @@
import { LogDescription } from "@ethersproject/abi";
import { BigNumber } from "@ethersproject/bignumber";
import { ReferenceSBTDynamicSelfSovereign } from "@masa-finance/masa-contracts-identity";

Check failure on line 3 in src/contracts/contract-modules/sbt/dynamic/SSSBT/dynamic-sssbt-contract-wrapper.ts

View workflow job for this annotation

GitHub Actions / build-and-test

'"@masa-finance/masa-contracts-identity"' has no exported member named 'ReferenceSBTDynamicSelfSovereign'. Did you mean 'ReferenceSBTSelfSovereign'?
import type { TypedDataField } from "ethers";
import { PayableOverrides, TypedDataDomain } from "ethers";

import { Messages } from "../../../../../collections";
import type { PaymentMethod } from "../../../../../interface";
import {
generateSignatureDomain,
isNativeCurrency,
signTypedData,
} from "../../../../../utils";
import { DynamicSBTContractWrapper } from "../dynamic-sbt-contract-wrapper";

export class DynamicSSSBTContractWrapper<
Contract extends ReferenceSBTDynamicSelfSovereign,
> extends DynamicSBTContractWrapper<Contract> {
public readonly types = {
SetState: [
{ name: "account", type: "address" },
{ name: "state", type: "string" },
{ name: "value", type: "bool" },
{ name: "authorityAddress", type: "address" },
{ name: "signatureDate", type: "uint256" },
],
};

/**
* Signs an SBT based on its address
* @param name
* @param types
* @param value
*/
public signState = async (
name: string,
types: Record<string, Array<TypedDataField>>,
value: Record<string, string | BigNumber | number | boolean>,
): Promise<{
signature: string;
authorityAddress: string;
}> => {
const authorityAddress = await this.masa.config.signer.getAddress();

const { signature, domain } = await signTypedData(
this.contract,
this.masa.config.signer,
name,
types,
value,
);

await this.verify(
"Signing Dynamic SBT failed!",
this.contract,
domain,
types,
value,
signature,
authorityAddress,
);

return { signature, authorityAddress };
};

/**
*
* @param name
* @param types
* @param value
* @param signature
* @param authorityAddress
*/
protected prepareSetState = async (
name: string,
types: Record<string, Array<TypedDataField>>,
value: Record<string, string | BigNumber | number | boolean>,
signature: string,
authorityAddress: string,
): Promise<boolean> => {
const domain: TypedDataDomain = await generateSignatureDomain(
this.masa.config.signer,
name,
this.contract.address,
);

await this.verify(
"Verifying Dynamic SBT failed!",
this.contract,
domain,
types,
value,
signature,
authorityAddress,
);

return true;
};

/**
*
* @param receiver
* @param state
* @param stateValue
* @param signature
* @param signatureDate
* @param authorityAddress
*/
public setState = async (
receiver: string,
state: string,
stateValue: boolean,
signature: string,
signatureDate: number,
authorityAddress: string,
): Promise<boolean> => {
const value: {
account: string;
state: string;
value: boolean;
authorityAddress: string;
signatureDate: number;
} = {
account: receiver,
state,
value: stateValue,
authorityAddress,
signatureDate,
};

const {
"setState(address,string,bool,address,uint256,bytes)": setState,
estimateGas: {
"setState(address,string,bool,address,uint256,bytes)": estimateGas,
},
} = this.contract;

this.prepareSetState(
"adsasdads",
this.types,
value,
signature,
authorityAddress,
);

const dynamicSSSBTSetStateArguments: [
account: string,
state: string,
value: boolean,
authorityAddress: string,
signatureDate: number,
signature: string,
] = [
receiver,
state,
stateValue,
authorityAddress,
signatureDate,
signature,
];

const mintSSSBTOverrides: PayableOverrides = await this.createOverrides();

let gasLimit: BigNumber = await estimateGas(
...dynamicSSSBTSetStateArguments,
mintSSSBTOverrides,
);

if (this.masa.config.network?.gasSlippagePercentage) {
gasLimit = DynamicSSSBTContractWrapper.addSlippage(
gasLimit,
this.masa.config.network.gasSlippagePercentage,
);
}

const { wait, hash } = await setState(...dynamicSSSBTSetStateArguments, {
...mintSSSBTOverrides,
gasLimit,
});

console.log(
Messages.WaitingToFinalize(
hash,
this.masa.config.network?.blockExplorerUrls?.[0],
),
);

await wait();

return true;
};

/**
*
* @param paymentMethod
* @param receiver
*/
public mint = async (
paymentMethod: PaymentMethod,
receiver: string,
): Promise<boolean> => {
// current limit for SSSBT is 1 on the default installation
let limit: number = 1;

try {
limit = (await this.contract.maxSBTToMint()).toNumber();
} catch {
if (this.masa.config.verbose) {
console.info("Loading limit failed, falling back to 1!");
}
}

try {
const balance: BigNumber = await this.contract.balanceOf(receiver);

if (limit > 0 && balance.gte(limit)) {
console.error(
`Minting of SSSBT failed: '${receiver}' exceeded the limit of '${limit}'!`,
);
return false;
}
} catch (error: unknown) {
if (error instanceof Error) {
console.warn(error.message);
}
}

const { price, paymentAddress } = await this.getPrice(paymentMethod);

const mintSSSBTArguments: [
string, // paymentMethod string
] = [paymentAddress];

const mintSSSBTOverrides: PayableOverrides = await this.createOverrides(
isNativeCurrency(paymentMethod) ? price : undefined,
);

if (this.masa.config.verbose) {
console.dir(
{
mintSSSBTArguments,
mintSSSBTOverrides,
},
{
depth: null,
},
);
}

const {
"mint(address)": mint,
estimateGas: { "mint(address)": estimateGas },
} = this.contract;

let gasLimit: BigNumber = await estimateGas(
...mintSSSBTArguments,
mintSSSBTOverrides,
);

if (this.masa.config.network?.gasSlippagePercentage) {
gasLimit = DynamicSSSBTContractWrapper.addSlippage(
gasLimit,
this.masa.config.network.gasSlippagePercentage,
);
}

const { wait, hash } = await mint(...mintSSSBTArguments, {
...mintSSSBTOverrides,
gasLimit,
});

console.log(
Messages.WaitingToFinalize(
hash,
this.masa.config.network?.blockExplorerUrls?.[0],
),
);

const { logs } = await wait();

const parsedLogs = this.masa.contracts.parseLogs(logs, [this.contract]);

const mintEvent = parsedLogs.find(
(log: LogDescription) => log.name === "Mint",
);

if (mintEvent) {
const { args } = mintEvent;
console.log(
`Minted to token with ID: ${args._tokenId} receiver '${args._owner}'`,
);

return true;
}

return false;
};
}
@@ -0,0 +1,35 @@
import type { ReferenceSBTDynamicSelfSovereign } from "@masa-finance/masa-contracts-identity";

Check failure on line 1 in src/contracts/contract-modules/sbt/dynamic/SSSBT/dynamic-sssbt-contract.ts

View workflow job for this annotation

GitHub Actions / build-and-test

'"@masa-finance/masa-contracts-identity"' has no exported member named 'ReferenceSBTDynamicSelfSovereign'. Did you mean 'ReferenceSBTSelfSovereign'?
import { ReferenceSBTDynamicSelfSovereign__factory } from "@masa-finance/masa-contracts-identity";

Check failure on line 2 in src/contracts/contract-modules/sbt/dynamic/SSSBT/dynamic-sssbt-contract.ts

View workflow job for this annotation

GitHub Actions / build-and-test

'"@masa-finance/masa-contracts-identity"' has no exported member named 'ReferenceSBTDynamicSelfSovereign__factory'. Did you mean 'ReferenceSBTSelfSovereign__factory'?

import type { ContractFactory } from "../../../../../interface/contract-factory";
import { MasaSBTModuleBase } from "../../masa-sbt-module-base";
import { DynamicSSSBTContractWrapper } from "./dynamic-sssbt-contract-wrapper";

export class DynamicSSSBTContract extends MasaSBTModuleBase {
/**
*
* @param contract
*/
public attach = <Contract extends ReferenceSBTDynamicSelfSovereign>(
contract: Contract,
): DynamicSSSBTContractWrapper<Contract> => {
return new DynamicSSSBTContractWrapper(this.masa, this.instances, contract);
};

/**
*
* @param address
* @param factory
*/
public connect = async <Contract extends ReferenceSBTDynamicSelfSovereign>(
address: string,
factory: ContractFactory = ReferenceSBTDynamicSelfSovereign__factory,
): Promise<DynamicSSSBTContractWrapper<Contract>> => {
const contract: Contract = await this.loadSBTContract<Contract>(
address,
factory,
);

return this.attach<Contract>(contract);
};
}
2 changes: 2 additions & 0 deletions src/contracts/contract-modules/sbt/dynamic/SSSBT/index.ts
@@ -0,0 +1,2 @@
export * from "./dynamic-sssbt-contract";
export * from "./dynamic-sssbt-contract-wrapper";

0 comments on commit 7c9c6a2

Please sign in to comment.