Skip to content

Commit 52ac5ad

Browse files
feat(satp): add support for NFTs
Signed-off-by: Tomás Silva <[email protected]>
1 parent db55b93 commit 52ac5ad

File tree

88 files changed

+4499
-1238
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+4499
-1238
lines changed

packages/cactus-plugin-satp-hermes/src/main/solidity/contracts/SATPWrapperContract.sol

Lines changed: 124 additions & 61 deletions
Large diffs are not rendered by default.

packages/cactus-plugin-satp-hermes/src/main/solidity/generated/SATPWrapperContract.sol/SATPWrapperContract.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/cactus-plugin-satp-hermes/src/main/typescript/core/errors/satp-service-errors.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,12 @@ export class AmountMissingError extends SATPInternalError {
402402
this.errorType = SATPErrorType.MISSING_PARAMETER;
403403
}
404404
}
405+
export class UniqueTokenDescriptorMissingError extends SATPInternalError {
406+
constructor(tag: string, cause?: string | Error | null) {
407+
super(`${tag}, Unique Descriptor missing`, cause ?? null, 400);
408+
this.errorType = SATPErrorType.MISSING_PARAMETER;
409+
}
410+
}
405411
export class MissingRecipientError extends SATPInternalError {
406412
constructor(tag: string, cause?: string | Error | null) {
407413
super(`${tag}, Recipient is missing`, cause ?? null, 400);

packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage0-client-service.ts

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ClaimFormat,
44
MessageType,
55
WrapAssertionClaimSchema,
6+
TokenType,
67
} from "../../../generated/proto/cacti/satp/v02/common/message_pb";
78
import {
89
NewSessionRequest,
@@ -28,6 +29,7 @@ import {
2829
SignatureVerificationError,
2930
TokenIdMissingError,
3031
TransferContextIdError,
32+
UniqueTokenDescriptorMissingError,
3133
} from "../../errors/satp-service-errors";
3234
import { SATPSession } from "../../satp-session";
3335
import {
@@ -40,7 +42,10 @@ import {
4042
TimestampType,
4143
} from "../../session-utils";
4244
import { signatureVerifier } from "../data-verifier";
43-
import { type FungibleAsset } from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
45+
import {
46+
type FungibleAsset,
47+
type NonFungibleAsset,
48+
} from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
4449
import {
4550
SATPService,
4651
SATPServiceType,
@@ -453,25 +458,51 @@ export class Stage0ClientService extends SATPService {
453458
ledgerType: sessionData.senderAsset.networkId?.type as LedgerType,
454459
} as NetworkId;
455460

456-
const token: FungibleAsset = protoToAsset(
457-
sessionData.senderAsset,
458-
networkId,
459-
) as FungibleAsset;
460-
461-
if (token.id == undefined) {
462-
throw new TokenIdMissingError(fnTag);
463-
}
464-
465-
if (token.amount == undefined) {
466-
throw new AmountMissingError(fnTag);
461+
let token: FungibleAsset | NonFungibleAsset;
462+
463+
switch (sessionData.senderAsset.tokenType) {
464+
case TokenType.ERC20:
465+
case TokenType.NONSTANDARD_FUNGIBLE:
466+
this.Log.debug(`${fnTag}, Sender Asset is a fungible token`);
467+
token = protoToAsset(
468+
sessionData.senderAsset,
469+
networkId,
470+
) as FungibleAsset;
471+
if (token.id == undefined) {
472+
throw new TokenIdMissingError(fnTag);
473+
}
474+
if (token.amount == undefined) {
475+
throw new AmountMissingError(fnTag);
476+
}
477+
478+
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
479+
this.Log.debug(
480+
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${(token as FungibleAsset).amount.toString()}`,
481+
);
482+
break;
483+
case TokenType.ERC721:
484+
case TokenType.NONSTANDARD_NONFUNGIBLE:
485+
this.Log.debug(`${fnTag}, Sender Asset is a non fungible token`);
486+
token = protoToAsset(
487+
sessionData.senderAsset,
488+
networkId,
489+
) as NonFungibleAsset;
490+
if (token.id == undefined) {
491+
throw new TokenIdMissingError(fnTag);
492+
}
493+
if (token.uniqueDescriptor == undefined) {
494+
throw new UniqueTokenDescriptorMissingError(fnTag);
495+
}
496+
497+
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
498+
this.Log.debug(
499+
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${String((token as NonFungibleAsset).uniqueDescriptor)}`,
500+
);
501+
break;
502+
default:
503+
throw new Error("Unsupported asset type");
467504
}
468505

469-
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
470-
471-
this.Log.debug(
472-
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${(token as FungibleAsset).amount.toString()}`,
473-
);
474-
475506
const bridge = this.bridgeManager.getSATPExecutionLayer(
476507
networkId,
477508
this.claimFormat,

packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage2-client-service.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import {
4242
import { FailedToProcessError } from "../../errors/satp-handler-errors";
4343
import { create } from "@bufbuild/protobuf";
4444
import { BridgeManagerClientInterface } from "../../../cross-chain-mechanisms/bridge/interfaces/bridge-manager-client-interface";
45-
import { type FungibleAsset } from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
45+
import { type Asset } from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
4646
import { protoToAsset } from "../service-utils";
4747
import { LedgerType } from "@hyperledger/cactus-core-api";
4848
import { NetworkId } from "../../../public-api";
@@ -312,7 +312,6 @@ export class Stage2ClientService extends SATPService {
312312
});
313313
this.Log.info(`${fnTag}, Locking Asset...`);
314314
const assetId = sessionData.senderAsset?.tokenId;
315-
const amount = sessionData.senderAsset?.amount;
316315

317316
if (sessionData.senderAsset == undefined) {
318317
throw new LedgerAssetError(fnTag);
@@ -323,22 +322,27 @@ export class Stage2ClientService extends SATPService {
323322
ledgerType: sessionData.senderAsset.networkId?.type as LedgerType,
324323
} as NetworkId;
325324

326-
const token: FungibleAsset = protoToAsset(
325+
const token: Asset = protoToAsset(
327326
sessionData.senderAsset,
328327
networkId,
329-
) as FungibleAsset;
328+
) as Asset;
330329

331330
if (token.id == undefined) {
332331
throw new TokenIdMissingError(fnTag);
333332
}
334333

335-
if (token.amount == undefined) {
336-
throw new AmountMissingError(fnTag);
334+
if (!("amount" in token) && !("uniqueDescriptor" in token)) {
335+
throw new LedgerAssetError(fnTag);
337336
}
338337

339-
this.Log.debug(
340-
`${fnTag}, Lock Asset ID: ${assetId} amount: ${amount}`,
341-
);
338+
if ("amount" in token && token.amount == undefined) {
339+
throw new AmountMissingError(fnTag);
340+
} else {
341+
const amount = sessionData.senderAsset?.amount;
342+
this.Log.debug(
343+
`${fnTag}, Lock Asset ID: ${assetId} amount: ${amount}`,
344+
);
345+
}
342346

343347
const bridge = this.bridgeManager.getSATPExecutionLayer(
344348
networkId,

packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage3-client-service.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ClaimFormat,
55
CommonSatpSchema,
66
MessageType,
7+
TokenType,
78
} from "../../../generated/proto/cacti/satp/v02/common/message_pb";
89
import { SATP_VERSION } from "../../constants";
910
import {
@@ -46,13 +47,17 @@ import {
4647
MissingBridgeManagerError,
4748
SessionError,
4849
TokenIdMissingError,
50+
UniqueTokenDescriptorMissingError,
4951
} from "../../errors/satp-service-errors";
5052
import { FailedToProcessError } from "../../errors/satp-handler-errors";
5153
import { State } from "../../../generated/proto/cacti/satp/v02/session/session_pb";
5254
import { create } from "@bufbuild/protobuf";
5355
import { BridgeManagerClientInterface } from "../../../cross-chain-mechanisms/bridge/interfaces/bridge-manager-client-interface";
5456
import { LedgerType } from "@hyperledger/cactus-core-api";
55-
import { FungibleAsset } from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
57+
import {
58+
FungibleAsset,
59+
NonFungibleAsset,
60+
} from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
5661
import { protoToAsset } from "../service-utils";
5762
import { NetworkId } from "../../../public-api";
5863
import { context, SpanStatusCode } from "@opentelemetry/api";
@@ -806,23 +811,49 @@ export class Stage3ClientService extends SATPService {
806811
ledgerType: sessionData.senderAsset.networkId?.type as LedgerType,
807812
} as NetworkId;
808813

809-
const token: FungibleAsset = protoToAsset(
810-
sessionData.senderAsset,
811-
networkId,
812-
) as FungibleAsset;
813-
814-
if (token.id == undefined) {
815-
throw new TokenIdMissingError(fnTag);
816-
}
817-
818-
if (token.amount == undefined) {
819-
throw new AmountMissingError(fnTag);
814+
let token: FungibleAsset | NonFungibleAsset;
815+
let amount: number | undefined;
816+
817+
switch (sessionData.senderAsset.tokenType) {
818+
case TokenType.ERC20:
819+
case TokenType.NONSTANDARD_FUNGIBLE:
820+
token = protoToAsset(
821+
sessionData.senderAsset,
822+
networkId,
823+
) as FungibleAsset;
824+
if (token.id == undefined) {
825+
throw new TokenIdMissingError(fnTag);
826+
}
827+
if (token.amount == undefined) {
828+
throw new AmountMissingError(fnTag);
829+
}
830+
this.Log.debug(
831+
`${fnTag}, Burn Asset ID: ${token.id} amount: ${token.amount}`,
832+
);
833+
amount = Number(token.amount);
834+
break;
835+
case TokenType.ERC721:
836+
case TokenType.NONSTANDARD_NONFUNGIBLE:
837+
token = protoToAsset(
838+
sessionData.senderAsset,
839+
networkId,
840+
) as NonFungibleAsset;
841+
if (token.id == undefined) {
842+
throw new TokenIdMissingError(fnTag);
843+
}
844+
if (token.uniqueDescriptor == undefined) {
845+
throw new UniqueTokenDescriptorMissingError(fnTag);
846+
}
847+
this.Log.debug(
848+
`${fnTag}, Burn Asset ID: ${token.id} uniqueDescriptor: ${token.uniqueDescriptor}`,
849+
);
850+
break;
851+
default:
852+
throw new Error(
853+
`Unsupported asset type ${sessionData.senderAsset.tokenType}`,
854+
);
820855
}
821856

822-
this.Log.debug(
823-
`${fnTag}, Burn Asset ID: ${token.id} amount: ${token.amount}`,
824-
);
825-
826857
const bridge = this.bridgeManager.getSATPExecutionLayer(
827858
networkId,
828859
this.claimFormat,
@@ -832,10 +863,9 @@ export class Stage3ClientService extends SATPService {
832863

833864
const res = await bridge.burnAsset(token);
834865

835-
this.monitorService.incrementCounter(
836-
"burned_asset_amount",
837-
Number(token.amount),
838-
);
866+
if (amount != undefined) {
867+
this.monitorService.incrementCounter("burned_asset_amount", amount);
868+
}
839869

840870
sessionData.burnAssertionClaim.receipt = res.receipt;
841871

packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage0-server-service.ts

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import {
88
ClaimFormat,
99
MessageType,
10+
TokenType,
1011
WrapAssertionClaimSchema,
1112
} from "../../../generated/proto/cacti/satp/v02/common/message_pb";
1213
import {
@@ -32,6 +33,7 @@ import {
3233
SignatureMissingError,
3334
SignatureVerificationError,
3435
TokenIdMissingError,
36+
UniqueTokenDescriptorMissingError,
3537
} from "../../errors/satp-service-errors";
3638
import { SATPSession } from "../../satp-session";
3739
import {
@@ -45,6 +47,7 @@ import {
4547
import {
4648
createAssetId,
4749
type FungibleAsset,
50+
type NonFungibleAsset,
4851
} from "../../../cross-chain-mechanisms/bridge/ontology/assets/asset";
4952
import {
5053
SATPService,
@@ -665,25 +668,53 @@ export class Stage0ServerService extends SATPService {
665668
ledgerType: sessionData.receiverAsset.networkId?.type as LedgerType,
666669
} as NetworkId;
667670

668-
const token: FungibleAsset = protoToAsset(
669-
sessionData.receiverAsset,
670-
networkId,
671-
) as FungibleAsset;
672-
673-
if (token.id == undefined) {
674-
throw new TokenIdMissingError(fnTag);
675-
}
676-
677-
if (token.amount == undefined) {
678-
throw new AmountMissingError(fnTag);
671+
let token: FungibleAsset | NonFungibleAsset;
672+
673+
switch (sessionData.receiverAsset.tokenType) {
674+
case TokenType.ERC20:
675+
case TokenType.NONSTANDARD_FUNGIBLE:
676+
this.Log.debug(`${fnTag}, Receiver Asset is a fungible token`);
677+
token = protoToAsset(
678+
sessionData.receiverAsset,
679+
networkId,
680+
) as FungibleAsset;
681+
if (token.id == undefined) {
682+
throw new TokenIdMissingError(fnTag);
683+
}
684+
if (token.amount == undefined) {
685+
throw new AmountMissingError(fnTag);
686+
}
687+
688+
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
689+
this.Log.debug(
690+
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${(token as FungibleAsset).amount.toString()}`,
691+
);
692+
break;
693+
case TokenType.ERC721:
694+
case TokenType.NONSTANDARD_NONFUNGIBLE:
695+
this.Log.debug(
696+
`${fnTag}, Receiver Asset is a non fungible token`,
697+
);
698+
token = protoToAsset(
699+
sessionData.receiverAsset,
700+
networkId,
701+
) as NonFungibleAsset;
702+
if (token.id == undefined) {
703+
throw new TokenIdMissingError(fnTag);
704+
}
705+
if (token.uniqueDescriptor == undefined) {
706+
throw new UniqueTokenDescriptorMissingError(fnTag);
707+
}
708+
709+
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
710+
this.Log.debug(
711+
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${String((token as NonFungibleAsset).uniqueDescriptor)}`,
712+
);
713+
break;
714+
default:
715+
throw new Error("Unsupported asset type");
679716
}
680717

681-
this.Log.debug(`${fnTag}, Wrap: ${safeStableStringify(token)}`);
682-
683-
this.Log.debug(
684-
`${fnTag}, Wrap Asset ID: ${token.id} amount: ${(token as FungibleAsset).amount.toString()}`,
685-
);
686-
687718
const bridge = this.bridgeManager.getSATPExecutionLayer(
688719
networkId,
689720
this.claimFormat,

0 commit comments

Comments
 (0)