import axios from "axios";
import { ethers, randomBytes, Signer } from "ethers";
// ABI Interface for V2 Collateral Coordinator Contract
import { CoordinatorInterface } from "../lib/utils/abis/v2/Coordinator";
// Can be found at https://snowtrace.io/address/0xE09916E8777cf88E634578C3875CF54d20769fAa/contract/43114/code
import { CollateralInterface } from "../lib/utils/abis/v2/Collateral";
// Can be found at https://snowtrace.io/address/0xbc2F19427EE4224a561Bc04bF16C829B967beB11/contract/43114/code
import dotenv from "dotenv";
import { Services } from "../lib/utils/services";
dotenv.config();
type FetchV2SignatureOpts = {
userId: string; // Must be consumer issuing to use user withdraw endpoint
apiKey: string;
token: string; // Token to withdraw
amount: string; // Who much to withdraw
adminAddress: string; // Wallet address that is the collateral contract admin
recipientAddress: string; // Who to give the asset to
chainId: string; // Which chain the contracts reside
coordinatorAddress: string; // coordinator contract of collateral contract
};
const BASE_URL = "https://api-dev.rain.xyz";
const main = async ({
userId,
apiKey,
token,
amount,
adminAddress,
recipientAddress,
chainId,
coordinatorAddress,
}: FetchV2SignatureOpts) => {
// get chain - this can be any provider for the requested chain
const chain = (await Services.chains()).getById(chainId);
/**
* Setup signer to send transaction
* @dev this should be the admin of the collateral contract
*/
const signerPk = process.env.COLLATERAL_ADMIN_PK;
if (!signerPk) {
throw new Error("No signer key provided");
}
const signer = new ethers.Wallet(signerPk).connect(chain.fallbackProvider);
//build API request
const baseUrl = `${BASE_URL}/v1/issuing/users/${userId}/signatures/withdrawals`;
const params = {
token,
amount,
adminAddress,
recipientAddress,
chainId,
};
// request signature with api key
const signatureResponse = await axios.get(baseUrl, {
headers: {
"Api-Key": apiKey,
},
params,
});
// setup parameters from response
const signature = await signatureResponse.data;
const [
collateralProxy,
assetAddress,
amountInCents,
recipient,
expiresAt,
executorPublisherSalt,
executorPublisherSig,
] = signature.parameters;
// Get coordinator & withdrawAsset interface
const coordinatorContract = new ethers.Contract(coordinatorAddress, CoordinatorInterface).connect(signer);
const withdrawAsset = coordinatorContract.getFunction("withdrawAsset");
// Get Collateral & nonce interface
const collateralContract = new ethers.Contract(collateralProxy, CollateralInterface).connect(signer);
const adminNonceFunction = collateralContract.getFunction("adminNonce");
const nonce = await adminNonceFunction.staticCallResult();
// Generate admin signature
const { salt: adminSalt, signature: adminSignature } = await getAdminSignature({
signer,
amount: amountInCents,
chainId: Number(chainId),
collateralProxyAddress: collateralProxy,
recipientAddress: recipient,
tokenAddress: assetAddress,
nonce: nonce[0],
});
const directTransfer = true;
// build transaction input
const functionInputs = [
collateralProxy,
assetAddress,
amountInCents,
recipient,
expiresAt,
Buffer.from(executorPublisherSalt, "base64"),
executorPublisherSig,
[adminSalt], // user generated
[adminSignature], // user generated
directTransfer,
];
// send withdrawAsset transaction
await withdrawAsset(...functionInputs);
};