Skip to content

Commit

Permalink
feat(casper): import methods
Browse files Browse the repository at this point in the history
  • Loading branch information
imsk17 committed Nov 5, 2024
1 parent 8bcbc15 commit f696414
Show file tree
Hide file tree
Showing 6 changed files with 549 additions and 15 deletions.
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"src/handlers/ton/nftc.ts",
"src/handlers/ton/nfti.ts",
"src/handlers/ton/tep64.ts",
"src/handlers/icp/nft.wasm.gz.hex.ts"
"src/handlers/icp/nft.wasm.gz.hex.ts",
"src/handlers/casper/get-deploy.ts"
]
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"@xp/cosmos-client": "git+https://github.com/XP-NETWORK/cosmos-client#bleeding-edge",
"aptos": "^1.21.0",
"axios": "^1.6.7",
"casper-cep78-js-client": "^1.5.1",
"casper-js-sdk": "^3.0.0-rc05",
"ethers": "^6.10.0",
"hashconnect": "^0.2.9",
"near-api-js": "^5.0.0",
Expand Down
41 changes: 41 additions & 0 deletions src/handlers/casper/get-deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { CasperClient } from "casper-js-sdk";

export const sleep = (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
export const getDeploy = async (client: CasperClient, deployHash: string) => {
let i = 300;
while (i !== 0) {
try {
const [_, raw] = await client.getDeploy(deployHash);
//@ts-ignore
if (raw.execution_results.length !== 0) {
// @ts-ignore
if (raw.execution_results[0].result.Success) {
return raw;
} else {
// @ts-ignore
throw Error(
"Contract execution: " +
// @ts-ignore
raw.execution_results[0].result.Failure.error_message,
);
}
} else {
i--;
await sleep(4000);
continue;
}
} catch (e: any) {
console.log(e.message);
if (e.message.match(/(deploy not known|no such deploy)/gim)) {
i--;
await sleep(4000);
continue;
} else {
throw e;
}
}
}
throw Error("Timeout after " + i + "s. Something's wrong");
};
199 changes: 199 additions & 0 deletions src/handlers/casper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { CEP78Client } from "casper-cep78-js-client";
import {
CLAccountHash,
CLByteArray,
CLPublicKey,
CLString,
CasperClient,
Contracts,
DeployUtil,
PurseIdentifier,
} from "casper-js-sdk";
import { getDeploy } from "./get-deploy";
import { TCasperHandler, TCasperParams } from "./types";

export function casperHandler({
rpc,
identifier,
network,
bridge,
storage,
}: TCasperParams): TCasperHandler {
const cc = new CasperClient(rpc);

// biome-ignore lint/suspicious/noExplicitAny: <explanation>
async function signWithCasperWallet(sender: any, deploy: DeployUtil.Deploy) {
const address = await sender.getActivePublicKey();
const signedDeployJson = await sender.sign(
JSON.stringify(DeployUtil.deployToJson(deploy)),
address,
);

const signedDeploy = DeployUtil.setSignature(
deploy,
signedDeployJson.signature,
CLPublicKey.fromHex(address),
);

const res = await cc.putDeploy(signedDeploy).catch((e) => {
console.log(e, "e in signWithCasperWallet");
return "";
});

res && (await getDeploy(cc, res));
return res;
}

return {
async getBalance(signer) {
const pubk = await signer.getActivePublicKey();
const balance = await cc.nodeClient.queryBalance(
PurseIdentifier.MainPurseUnderPublicKey,
pubk,
);
return balance.toBigInt();
},
deployNftCollection(signer, da, ga) {
unimplemented("deploy nft collection", signer, da, ga);
},
async nftData(tokenId, contract) {
const ctr = new Contracts.Contract(cc);
ctr.setContractHash(`hash-${contract}`);

const cn = await ctr.queryContractData(["collection_name"]);
const cs = await ctr.queryContractData(["collection_symbol"]);
const md = ((await ctr
.queryContractDictionary("metadata_raw", tokenId)
.catch(() => {
console.log(
`Failed to get raw metadata for ${contract} - ${tokenId}`,
);
return undefined;
})) ||
(await ctr
.queryContractDictionary("metadata_custom_validated", tokenId)
.catch(() => {
console.log(
`Failed to get custom validated metadata for ${contract} - ${tokenId}`,
);
throw new Error(
`Failed to get metadata for ${contract} - ${tokenId}`,
);
}))) as CLString;

return {
metadata: md.data,
name: cn,
royalty: 0n,
symbol: cs,
};
},
identifier,
getProvider() {
return cc;
},
decodeLockedEvent(txHash) {
unimplemented("decode tx hash", txHash);
},
claimNft(signer, claimData, sig, extraArgs) {
unimplemented("claim nft", signer, claimData, sig, extraArgs);
},
getValidatorCount() {
unimplemented();
},
lockNft(
signer,
sourceNft,
destinationChain,
to,
tokenId,
metaDataUri,
extraArgs,
) {
unimplemented(
"lock nft",
signer,
sourceNft,
destinationChain,
tokenId,
metaDataUri,
extraArgs,
to,
);
},
async mintNft(signer, ma) {
const nft = new CEP78Client(rpc, network);
nft.setContractHash(ma.contract);
const deploy = nft.mint(
{
meta: {
uri: ma.uri,
},
owner: ma.owner,
collectionName: ma.collectionName,
},
{
useSessionCode: false,
},
"1000000000",
CLPublicKey.fromFormattedString(await signer.getActivePublicKey()),
);
if (isBrowser()) {
return signWithCasperWallet(signer, deploy);
}

const signed = await signer.sign(
DeployUtil.deployToJson(deploy),
await signer.getActivePublicKey(),
);
return DeployUtil.deployFromJson(signed).unwrap().send(rpc);
},
getStorageContract() {
return storage;
},
validateAddress(hex) {
try {
CLAccountHash.fromFormattedString(hex);
return Promise.resolve(true);
} catch (e) {
return Promise.resolve(false);
}
},
transform(input) {
unimplemented("Transform", input);
},
async approveNft(signer, tokenId, contract, _) {
const cep78Client = new CEP78Client(rpc, network);
cep78Client.setContractHash(contract);
const deploy = cep78Client.approve(
{
operator: new CLByteArray(Buffer.from(bridge.split("-")[1], "hex")),
// tokenHash: tokenHash,
tokenId: tokenId,
},
"2000000000",
CLPublicKey.fromHex(await signer.getActivePublicKey()),
);

if (isBrowser()) {
return signWithCasperWallet(signer, deploy);
}

const signed = await signer.sign(
DeployUtil.deployToJson(deploy),
await signer.getActivePublicKey(),
);
const dep = cc.deployFromJson(signed).unwrap();
return await cc.putDeploy(dep);
},
};
}

function unimplemented(msg?: string, ...args: unknown[]): never {
throw new Error(`Unimplemented: ${msg}. ${JSON.stringify(args)}`);
}

function isBrowser() {
//@ts-ignore
return window !== undefined;
}
55 changes: 55 additions & 0 deletions src/handlers/casper/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { CasperClient } from "casper-js-sdk";
import { CasperLabsHelper } from "casper-js-sdk/dist/@types/casperlabsSigner";
import { BridgeStorage } from "../../contractsTypes/evm";
import { DeployNFTCollection, MintNft, TSingularNftChain } from "../types";

export type TCasperMintArgs = {
contract: `hash-${string}`;
name: string;
uri: string;
owner: string;
collectionName?: string;
};

export type CasperSigner = CasperLabsHelper;

export type TClaimData = {
destinationUserAddress: string;
name: string;
uri: string;
royaltyPercentage: bigint;
royaltyReceiver: string;
fee: bigint;
destination_chain: string;
source_chain: string;
source_nft_contract_address: string;
token_id: bigint;
transaction_hash: string;
nft_type: string;
metadata: string;
symbol: string;
amount: bigint;
};

export type TCasperHandler = TSingularNftChain<
CasperSigner,
TClaimData,
never,
string,
CasperClient
> &
MintNft<CasperSigner, TCasperMintArgs, never, string> &
DeployNFTCollection<
CasperSigner,
{ name: string; symbol: string },
never,
string
>;

export type TCasperParams = {
bridge: string;
rpc: string;
storage: BridgeStorage;
identifier: string;
network: string;
};
Loading

0 comments on commit f696414

Please sign in to comment.