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

Starknet #17

Merged
merged 9 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 2 additions & 1 deletion examples/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"@irys/web-upload": "workspace:^",
"@irys/web-upload-ethereum": "workspace:^",
"@irys/web-upload-ethereum-ethers-v6": "workspace:^",
"@irys/web-upload-ethereum-viem-v2": "workspace:^"
"@irys/web-upload-ethereum-viem-v2": "workspace:^",
"@irys/upload-starknet-node":"workspace:^"
},
"version": "1.0.2",
"scripts": {},
Expand Down
11 changes: 10 additions & 1 deletion examples/node/scripts/test-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { canUploadUsdcEth } from "./tokens/usdcEth";
import { canUploadUsdcPolygon } from "./tokens/usdcPolygon";
import { canUploadChainlink } from "./tokens/chainlink";
import { canUploadSolana } from "./tokens/solana";
import {canUploadStarknet} from "./tokens/starknet"

const runTests = async () => {

Expand Down Expand Up @@ -96,8 +97,16 @@ const runTests = async () => {
const usdcPolygonResult = await canUploadUsdcPolygon();
if (usdcPolygonResult) console.log("USDC on Polygon upload test passed.");
else console.log("USDC on Polygon upload test failed.");


const uploadStarknet = await canUploadStarknet()
if(uploadStarknet)console.log("STRK on Starknet upload test passed.");
else console.log("STRK on Starknet upload test failed.");


};

runTests().catch((err) => console.error("Unexpected error during testing:", err));




2 changes: 1 addition & 1 deletion packages/aptos-node/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class AptosConfig extends BaseNodeToken {
};
}

ownerToAddress(owner: any): string {
async ownerToAddress(owner: any): Promise<string> {
const hash = sha3.sha3_256.create();
hash.update(Buffer.from(owner));
hash.update("\x00");
Expand Down
153 changes: 105 additions & 48 deletions packages/aptos-web/src/token.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { Network, PendingTransactionResponse, UserTransactionResponse } from "@aptos-labs/ts-sdk";
import type {
Network,
PendingTransactionResponse,
UserTransactionResponse,
} from '@aptos-labs/ts-sdk';
import {
Aptos,
AptosConfig as AptosSDKConfig,
Expand All @@ -11,13 +15,13 @@ import {
SignedTransaction,
generateSignedTransaction,
generateSigningMessageForTransaction,
} from "@aptos-labs/ts-sdk";
import type { Signer } from "@irys/bundles";
import { InjectedAptosSigner, AptosSigner } from "@irys/bundles/web";
import BigNumber from "bignumber.js";
import type { TokenConfig, Tx } from "@irys/upload-core";
import sha3 from "js-sha3";
import BaseWebToken from "@irys/web-upload/tokens/base";
} from '@aptos-labs/ts-sdk';
import type { Signer } from '@irys/bundles';
import { InjectedAptosSigner, AptosSigner } from '@irys/bundles/web';
import BigNumber from 'bignumber.js';
import type { TokenConfig, Tx } from '@irys/upload-core';
import sha3 from 'js-sha3';
import BaseWebToken from '@irys/web-upload/tokens/base';

export type SignMessagePayload = {
address?: boolean; // Should we include the address of the account in the message
Expand Down Expand Up @@ -67,7 +71,7 @@ export default class AptosConfig extends BaseWebToken {
super(config);
this.signingFn = config?.opts?.signingFunction;

this.base = ["octa", 1e8];
this.base = ['octa', 1e8];
}

async getProvider(): Promise<Aptos> {
Expand All @@ -76,23 +80,25 @@ export default class AptosConfig extends BaseWebToken {

async getTx(txId: string): Promise<Tx> {
const client = await this.getProvider();
const tx = (await client.waitForTransaction({ transactionHash: txId })) as any;
const tx = (await client.waitForTransaction({
transactionHash: txId,
})) as any;
const payload = tx?.payload as any;

if (!tx.success) {
throw new Error(tx?.vm_status ?? "Unknown Aptos error");
throw new Error(tx?.vm_status ?? 'Unknown Aptos error');
}

if (
!(
payload?.function === "0x1::coin::transfer" &&
payload?.type_arguments[0] === "0x1::aptos_coin::AptosCoin" &&
tx?.vm_status === "Executed successfully"
payload?.function === '0x1::coin::transfer' &&
payload?.type_arguments[0] === '0x1::aptos_coin::AptosCoin' &&
tx?.vm_status === 'Executed successfully'
)
) {
throw new Error(`Aptos tx ${txId} failed validation`);
}
const isPending = tx.type === "pending_transaction";
const isPending = tx.type === 'pending_transaction';
return {
to: payload.arguments[0],
from: tx.sender,
Expand All @@ -102,10 +108,10 @@ export default class AptosConfig extends BaseWebToken {
};
}

ownerToAddress(owner: any): string {
async ownerToAddress(owner: any): Promise<string> {
const hash = sha3.sha3_256.create();
hash.update(Buffer.from(owner));
hash.update("\x00");
hash.update('\x00');
return `0x${hash.hex()}`;
}

Expand All @@ -116,59 +122,97 @@ export default class AptosConfig extends BaseWebToken {
getSigner(): Signer {
if (this.signerInstance) return this.signerInstance;
if (this.signingFn) {
const signer = new AptosSigner("", "0x" + this._publicKey.toString("hex"));
const signer = new AptosSigner(
'',
'0x' + this._publicKey.toString('hex')
);
signer.sign = this.signingFn; // override signer fn
return (this.signerInstance = signer);
}
return (this.signerInstance = new InjectedAptosSigner(this.wallet, this._publicKey));
return (this.signerInstance = new InjectedAptosSigner(
this.wallet,
this._publicKey
));
}

async verify(pub: any, data: Uint8Array, signature: Uint8Array): Promise<boolean> {
async verify(
pub: any,
data: Uint8Array,
signature: Uint8Array
): Promise<boolean> {
return await InjectedAptosSigner.verify(pub, data, signature);
}

async getCurrentHeight(): Promise<BigNumber> {
return new BigNumber(((await (await this.getProvider()).getLedgerInfo()) as { block_height: string }).block_height);
return new BigNumber(
(
(await (await this.getProvider()).getLedgerInfo()) as {
block_height: string;
}
).block_height
);
}

async getFee(amount: BigNumber.Value, to?: string): Promise<{ gasUnitPrice: number; maxGasAmount: number }> {
async getFee(
amount: BigNumber.Value,
to?: string
): Promise<{ gasUnitPrice: number; maxGasAmount: number }> {
const client = await this.getProvider();

if (!this.address) throw new Error("Address is undefined - you might be missing a wallet, or have not run Irys.ready()");
if (!this.address)
throw new Error(
'Address is undefined - you might be missing a wallet, or have not run Irys.ready()'
);

const transaction = await client.transaction.build.simple({
sender: this.address,
data: {
function: "0x1::coin::transfer",
typeArguments: ["0x1::aptos_coin::AptosCoin"],
functionArguments: [to ?? "0x149f7dc9c8e43c14ab46d3a6b62cfe84d67668f764277411f98732bf6718acf9", new BigNumber(amount).toNumber()],
function: '0x1::coin::transfer',
typeArguments: ['0x1::aptos_coin::AptosCoin'],
functionArguments: [
to ??
'0x149f7dc9c8e43c14ab46d3a6b62cfe84d67668f764277411f98732bf6718acf9',
new BigNumber(amount).toNumber(),
],
},
});

const accountAuthenticator = new AccountAuthenticatorEd25519(
new Ed25519PublicKey(await this.getPublicKey()),
new Ed25519Signature(new Uint8Array(64)),
new Ed25519Signature(new Uint8Array(64))
);

const transactionAuthenticator = new TransactionAuthenticatorEd25519(accountAuthenticator.public_key, accountAuthenticator.signature);
const transactionAuthenticator = new TransactionAuthenticatorEd25519(
accountAuthenticator.public_key,
accountAuthenticator.signature
);

const signedSimulation = new SignedTransaction(transaction.rawTransaction, transactionAuthenticator).bcsToBytes();
const signedSimulation = new SignedTransaction(
transaction.rawTransaction,
transactionAuthenticator
).bcsToBytes();

const queryParams = {
estimate_gas_unit_price: true,
estimate_max_gas_amount: true,
};

const { data } = await postAptosFullNode<Uint8Array, UserTransactionResponse[]>({
const { data } = await postAptosFullNode<
Uint8Array,
UserTransactionResponse[]
>({
aptosConfig: this.aptosConfig,
body: signedSimulation,
path: "transactions/simulate",
path: 'transactions/simulate',
params: queryParams,
originMethod: "simulateTransaction",
originMethod: 'simulateTransaction',
contentType: MimeType.BCS_SIGNED_TRANSACTION,
});

return { gasUnitPrice: +data[0].gas_unit_price, maxGasAmount: +data[0].max_gas_amount };
return {
gasUnitPrice: +data[0].gas_unit_price,
maxGasAmount: +data[0].max_gas_amount,
};

// const simulationResult = await client.simulateTransaction(this.accountInstance, rawTransaction, { estimateGasUnitPrice: true, estimateMaxGasAmount: true });
// return new BigNumber(simulationResult?.[0].gas_unit_price).multipliedBy(simulationResult?.[0].gas_used);
Expand All @@ -177,15 +221,19 @@ export default class AptosConfig extends BaseWebToken {
}

async sendTx(data: any): Promise<string | undefined> {
if (!this.signingFn) return (await this.wallet.signAndSubmitTransaction(data)).hash;
if (!this.signingFn)
return (await this.wallet.signAndSubmitTransaction(data)).hash;
// return (await (await (this.getProvider())).submitSignedBCSTransaction(data)).hash;
const provider = await this.getProvider();

const { data: postData } = await postAptosFullNode<Uint8Array, PendingTransactionResponse>({
const { data: postData } = await postAptosFullNode<
Uint8Array,
PendingTransactionResponse
>({
aptosConfig: this.aptosConfig,
body: data,
path: "transactions",
originMethod: "submitTransaction",
path: 'transactions',
originMethod: 'submitTransaction',
contentType: MimeType.BCS_SIGNED_TRANSACTION,
});

Expand All @@ -196,13 +244,13 @@ export default class AptosConfig extends BaseWebToken {
async createTx(
amount: BigNumber.Value,
to: string,
fee?: { gasUnitPrice: number; maxGasAmount: number },
fee?: { gasUnitPrice: number; maxGasAmount: number }
): Promise<{ txId: string | undefined; tx: any }> {
const txData = {
sender: this.address!,
data: {
function: "0x1::coin::transfer",
typeArguments: ["0x1::aptos_coin::AptosCoin"],
function: '0x1::coin::transfer',
typeArguments: ['0x1::aptos_coin::AptosCoin'],
functionArguments: [to, new BigNumber(amount).toNumber()],
},
options: {
Expand All @@ -224,10 +272,13 @@ export default class AptosConfig extends BaseWebToken {

const senderAuthenticator = new AccountAuthenticatorEd25519(
new Ed25519PublicKey(await this.getPublicKey()),
new Ed25519Signature(signerSignature),
new Ed25519Signature(signerSignature)
);

const signedTransaction = generateSignedTransaction({ transaction, senderAuthenticator });
const signedTransaction = generateSignedTransaction({
transaction,
senderAuthenticator,
});
return { txId: undefined, tx: signedTransaction };
// const rawTransaction = await client.generateRawTransaction(this.accountInstance.address(), payload);
// const bcsTxn = AptosClient.generateBCSTransaction(this.accountInstance, rawTransaction);
Expand All @@ -239,26 +290,32 @@ export default class AptosConfig extends BaseWebToken {

async getPublicKey(): Promise<string | Buffer> {
return (this._publicKey ??= this.signingFn
? (Buffer.from((this.wallet as unknown as string).slice(2), "hex") as unknown as Buffer)
: Buffer.from(this.wallet.account.publicKey.toString().slice(2), "hex"));
? (Buffer.from(
(this.wallet as unknown as string).slice(2),
'hex'
) as unknown as Buffer)
: Buffer.from(this.wallet.account.publicKey.toString().slice(2), 'hex'));
}

public async ready(): Promise<void> {
// In the Aptos context, this.providerUrl is the Aptos Network enum type we want
// to work with. read more https://github.com/aptos-labs/aptos-ts-sdk/blob/main/src/api/aptosConfig.ts#L14
// this.providerUrl is a Network enum type represents the current configured network
this.aptosConfig = new AptosSDKConfig({ network: this.providerUrl, ...this.config?.opts?.aptosSdkConfig });
this.aptosConfig = new AptosSDKConfig({
network: this.providerUrl,
...this.config?.opts?.aptosSdkConfig,
});
this._publicKey = (await this.getPublicKey()) as Buffer;
this._address = this.ownerToAddress(this._publicKey);
this._address = await this.ownerToAddress(this._publicKey);

const client = await this.getProvider();

this._address = await client
.lookupOriginalAccountAddress({ authenticationKey: this.address ?? "" })
.lookupOriginalAccountAddress({ authenticationKey: this.address ?? '' })
.then((hs) => hs.toString())
.catch((_) => this._address); // fallback to original

if (this._address?.length == 66 && this._address.charAt(2) === "0") {
if (this._address?.length == 66 && this._address.charAt(2) === '0') {
this._address = this._address.slice(0, 2) + this._address.slice(3);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ethereum-web/src/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class EthereumConfig extends BaseWebToken {
};
}

ownerToAddress(owner: any): string {
ownerToAddress(owner: any): Promise<string> {
// return (
// "0x" +
// keccak256(Buffer.from(owner.slice(1)))
Expand Down
2 changes: 1 addition & 1 deletion packages/ethereum/src/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default class BaseEthereumToken extends BaseNodeToken {
};
}

ownerToAddress(owner: any): string {
async ownerToAddress(owner: any): Promise<string> {
return "0x" + keccak256(owner.slice(1)).slice(-20).toString("hex");
}

Expand Down
2 changes: 1 addition & 1 deletion packages/solana-node/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class SolanaConfig extends BaseNodeToken {
return tx;
}

ownerToAddress(owner: any): string {
async ownerToAddress(owner: any): Promise<string> {
return bs58.encode(owner);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/solana-web/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default class SolanaConfig extends BaseWebToken {
return tx;
}

ownerToAddress(owner: any): string {
async ownerToAddress(owner: any): Promise<string> {
if (typeof owner === "string") {
owner = Buffer.from(owner);
}
Expand Down
9 changes: 9 additions & 0 deletions packages/starknet-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# starknet-node

TODO

## Installation

```sh
npm install @irys/upload-starknet-node
```
11 changes: 11 additions & 0 deletions packages/starknet-node/cjs.tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../cjs.tsconfig.json",
"include": [
"src"
],
"compilerOptions": {
"outDir": "dist/cjs",
"rootDir": "./src",
"declaration": false
}
}
Loading