@kanalabs/paymaster-sdk
Version:
Kanalab's Paymaster SDK
400 lines (399 loc) • 20.9 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PaymasterSdk = void 0;
const ts_sdk_1 = require("@aptos-labs/ts-sdk");
const constants_1 = require("./constants");
const cross_fetch_1 = __importDefault(require("cross-fetch"));
// PaymasterSdk class for interacting with the Kanalabs paymaster API.
class PaymasterSdk {
// PaymasterSdk constructor.
// @param walletProvider - Wallet provider configuration.
// @param optionsLike - SDK options.
constructor(walletProvider, optionsLike) {
var _a;
// Base URL for Gas Service API
this.baseUrl = constants_1.PAYMASTER_BASE_URL;
if (optionsLike.network !== ts_sdk_1.Network.MAINNET &&
optionsLike.network !== ts_sdk_1.Network.TESTNET &&
optionsLike.network !== undefined) {
throw new Error('Invalid network');
}
const config = new ts_sdk_1.AptosConfig(Object.assign({ network: (_a = optionsLike.network) !== null && _a !== void 0 ? _a : ts_sdk_1.Network.MAINNET, fullnode: optionsLike.nodeUrl !== null
? optionsLike.nodeUrl
: optionsLike.network === ts_sdk_1.Network.TESTNET
? constants_1.TESTNET_NODE_URL
: constants_1.MAINNET_NODE_URL }, (optionsLike.aptosApiKey && { clientConfig: { API_KEY: optionsLike.aptosApiKey } })));
this.network = optionsLike.network;
this.projectKey = optionsLike.projectKey;
this.aptosClient = new ts_sdk_1.Aptos(config);
this.wallet = walletProvider.privateKey
? ts_sdk_1.Account.fromPrivateKey({
privateKey: new ts_sdk_1.Ed25519PrivateKey(walletProvider.privateKey),
})
: undefined;
}
/**
* @deprecated This endpoint is deprecated because Aptos accounts do not need to be manually initialized anymore.
* Initialize the user's account.
* @returns Success and message information.
*/
initAccount(args) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const address = (args === null || args === void 0 ? void 0 : args.address)
? args.address
: this.wallet
? this.wallet.accountAddress.toString()
: (() => {
throw new Error('No address provided');
})();
const url = `${this.baseUrl}/initAccount`;
const query = { address: address, coin: (_a = args === null || args === void 0 ? void 0 : args.coin) !== null && _a !== void 0 ? _a : '' };
const params = new URLSearchParams(query).toString();
const headers = this.getCommonHeaders();
try {
const response = yield (0, cross_fetch_1.default)(`${url}?${params}`, { headers });
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in initializing Aptos account for user.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || (error === null || error === void 0 ? void 0 : error.message) || error;
}
});
}
// Add the user to the whitelist.
// @returns Success and message information.
addToWhitelist(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/addToWhitelist`;
const address = (args === null || args === void 0 ? void 0 : args.address)
? args.address
: this.wallet
? this.wallet.accountAddress.toString()
: (() => {
throw new Error('No address provided');
})();
const query = { user_address: address };
const params = new URLSearchParams(query).toString();
const headers = this.getCommonHeaders();
try {
const response = yield (0, cross_fetch_1.default)(`${url}?${params}`, { headers, method: 'GET' });
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in adding user to whitelist.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
// Disables user on the whitelist to stop sponsored txns.
// @returns Success and message information.
disableUser(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/modifyUserState`;
const address = (args === null || args === void 0 ? void 0 : args.address)
? args.address
: this.wallet
? this.wallet.accountAddress.toString()
: (() => {
throw new Error('No address provided');
})();
const query = { user_address: address, status: 'false' };
const params = new URLSearchParams(query).toString();
const headers = this.getCommonHeaders();
try {
const response = yield (0, cross_fetch_1.default)(`${url}?${params}`, { headers, method: 'GET' });
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in disabling user.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
// Enables user on the whitelist to start sponsored txns.
// @returns Success and message information.
enableUser(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/modifyUserState`;
const address = (args === null || args === void 0 ? void 0 : args.address)
? args.address
: this.wallet
? this.wallet.accountAddress.toString()
: (() => {
throw new Error('No address provided');
})();
const query = { user_address: address, status: 'true' };
const params = new URLSearchParams(query).toString();
const headers = this.getCommonHeaders();
try {
const response = yield (0, cross_fetch_1.default)(`${url}?${params}`, { headers, method: 'GET' });
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in enabling user.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
// Check if the user is whitelisted.
// @returns Success and message information.
isWhitelisted(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/isWhitelisted`;
const address = (args === null || args === void 0 ? void 0 : args.address)
? args.address
: this.wallet
? this.wallet.accountAddress.toString()
: (() => {
throw new Error('No address provided');
})();
const query = { address: address };
const params = new URLSearchParams(query).toString();
const headers = this.getCommonHeaders();
try {
const response = yield (0, cross_fetch_1.default)(`${url}?${params}`, { headers, method: 'GET' });
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in checking whitelist status.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
// Perform a sponsored transaction.
// @param payload - Transaction payload.
// @returns Pending transaction information.
sponsoredTxn(args) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
try {
if (this.wallet === undefined) {
throw new Error('No wallet');
}
const transaction = yield this.aptosClient.transaction.build.simple({
sender: this.wallet.accountAddress.toString(),
data: args.data,
options: args.options,
withFeePayer: true,
});
const senderAuth = this.aptosClient.transaction.sign({
signer: this.wallet,
transaction,
});
const rawTransactionBytes = transaction.rawTransaction.bcsToBytes();
const url = `${this.baseUrl}/sponsorGas`;
const headers = this.getCommonHeaders();
const response = yield (0, cross_fetch_1.default)(url, {
method: 'POST',
headers: headers,
body: JSON.stringify({ data: rawTransactionBytes }),
});
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in sponsoring transaction.');
});
}
const responseData = yield response.json();
const feePayerAddress = responseData.feePayerAddress;
const feepayerSignature = new Uint8Array(Object.values(responseData.feePayerAuth));
const deserializerFeePayer = new ts_sdk_1.Deserializer(feepayerSignature);
const feepayerAuth = ts_sdk_1.AccountAuthenticator.deserialize(deserializerFeePayer);
const committedTxn = yield this.aptosClient.transaction.submit.simple({
transaction: {
rawTransaction: transaction.rawTransaction,
feePayerAddress: ts_sdk_1.AccountAddress.fromString(feePayerAddress),
},
senderAuthenticator: senderAuth,
feePayerAuthenticator: feepayerAuth,
});
return committedTxn;
}
catch (error) {
throw ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) || error;
}
});
}
/// Perform a sponsored transaction with senderAuth and transaction bytes.
/// @param transaction - Generated transaction. SimpleTransaction or MultiAgentTransaction.
/// @param senderAuth - Sender authenticator.
/// @param additionalAuthenticators - Additional signer authenticators.
/// @param additionalAddresses - Secondary signer addresses.
/// @returns Pending transaction information.
sponsoredTxnWithSenderAuth(args) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
try {
const { transaction, senderAuth, additionalAuthenticators, additionalAddresses } = args;
const url = `${this.baseUrl}/sponsorGas`;
const headers = this.getCommonHeaders();
const rawTransactionBytes = transaction.rawTransaction.bcsToBytes();
const requestBody = { data: rawTransactionBytes };
if (additionalAuthenticators && additionalAddresses) {
if (additionalAuthenticators.length !== additionalAddresses.length) {
throw new Error('No of Additional Authenticators and address length mismatch');
}
requestBody.additionalSigners = additionalAddresses.map((address) => address.toString());
}
const response = yield (0, cross_fetch_1.default)(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(requestBody),
});
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in sponsoring transaction.');
});
}
const responseData = yield response.json();
const feePayerAddress = responseData.feePayerAddress;
const feepayerSignature = new Uint8Array(Object.values(responseData.feePayerAuth));
if (additionalAuthenticators && additionalAddresses) {
const deserializerFeePayer = new ts_sdk_1.Deserializer(feepayerSignature);
const feepayerAuth = ts_sdk_1.AccountAuthenticator.deserialize(deserializerFeePayer);
// For multi agent transaction
return yield this.aptosClient.transaction.submit.multiAgent({
transaction: {
rawTransaction: transaction.rawTransaction,
feePayerAddress: ts_sdk_1.AccountAddress.fromString(feePayerAddress),
secondarySignerAddresses: additionalAddresses,
},
senderAuthenticator: senderAuth,
feePayerAuthenticator: feepayerAuth,
additionalSignersAuthenticators: additionalAuthenticators,
});
}
else {
const deserializerFeePayer = new ts_sdk_1.Deserializer(feepayerSignature);
const feepayerAuth = ts_sdk_1.AccountAuthenticator.deserialize(deserializerFeePayer);
// For simple transaction
return yield this.aptosClient.transaction.submit.simple({
transaction: {
rawTransaction: transaction.rawTransaction,
feePayerAddress: ts_sdk_1.AccountAddress.fromString(feePayerAddress),
},
senderAuthenticator: senderAuth,
feePayerAuthenticator: feepayerAuth,
});
}
}
catch (error) {
throw ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) || error;
}
});
}
addWhitelistFunctions(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/addWhitelistFunctions`;
const headers = this.getCommonHeaders();
try {
// Send a POST request to the server with the functions data in the body
const response = yield (0, cross_fetch_1.default)(url, {
method: 'POST',
headers: headers,
body: JSON.stringify({ functions: args.functions, signature: args.signature, publicKey: args.publicKey }),
});
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in adding whitelist functions.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
addModuleWhitelistFunctions(args) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/addModuleWhitelistFunctions`;
const headers = this.getCommonHeaders();
try {
// Send a POST request to the server with the functions data in the body
const response = yield (0, cross_fetch_1.default)(url, {
method: 'POST',
headers: headers,
body: JSON.stringify({ functions: args.functions, signature: args.signature, publicKey: args.publicKey }),
});
if (response.status >= 400) {
yield response.json().then((data) => {
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error in adding module whitelist functions.');
});
}
return yield response.json();
}
catch (error) {
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
getDappFeePayerAddress() {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.baseUrl}/getDappFeePayerAddress`;
const headers = this.getCommonHeaders();
try {
// Send a GET request with headers
const response = yield (0, cross_fetch_1.default)(url, {
method: 'GET',
headers: headers,
});
// Check for errors in the response
if (response.status >= 400) {
const data = yield response.json();
throw new Error((data === null || data === void 0 ? void 0 : data.error) || (data === null || data === void 0 ? void 0 : data.message) || 'Error fetching dApp Fee Payer Address.');
}
// Return the parsed response JSON
return yield response.json();
}
catch (error) {
// Re-throw the error with relevant details
throw (error === null || error === void 0 ? void 0 : error.data) || error;
}
});
}
// Get common headers for requests.
// @returns Common headers.
getCommonHeaders() {
var _a, _b;
return {
'Content-Type': 'application/json',
'api-key': this.projectKey,
network: (_a = this.network) !== null && _a !== void 0 ? _a : ts_sdk_1.Network.MAINNET,
chain: (_b = this.chain) !== null && _b !== void 0 ? _b : constants_1.chainName.Aptos,
};
}
}
exports.PaymasterSdk = PaymasterSdk;