@secux/app-sol
Version:
SecuX Hardware Wallet SOL API
18 lines (15 loc) • 8.5 kB
JavaScript
;
/*!
Copyright 2022 SecuX Technology Inc
Copyright Chen Wei-En
Copyright Wu Tsung-Yu
Licensed under the Apache License, Version 2.0 (the License);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an AS IS BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/Object.defineProperty(exports,"__esModule",{value:!0}),exports.SecuxSOL=void 0;const ow_1=require("ow"),ow_2=require("ow"),bs58_1=require("@secux/utility/lib/bs58"),protocol_transaction_1=require("@secux/protocol-transaction"),interface_1=require("@secux/protocol-transaction/lib/interface"),communication_1=require("@secux/utility/lib/communication"),transport_1=require("@secux/transport"),interface_2=require("./interface"),transaction_1=require("./transaction"),utility_1=require("@secux/utility"),utils_1=require("./utils"),instruction_1=require("./instruction"),action_1=require("./action"),logger=null===utility_1.Logger||void 0===utility_1.Logger?void 0:utility_1.Logger.child({id:"app-sol"}),mcu={crypto:"2.23",nifty:"2.06"};class SecuxSOL{static get Action(){return action_1.Action}static addressConvert(publickey,option){var _a;(0,ow_1.default)(publickey,interface_2.ow_publickey);const pk="string"==typeof(data=publickey)?Buffer.from(data,"hex"):data;var data;if(!option)return bs58_1.Base58.encode(pk);if(option.seed){(0,ow_1.default)(option,interface_2.ow_SeedOption);const newPubkey=(0,utils_1.createWithSeed)(pk,option.seed,bs58_1.Base58.decode(option.programId));return bs58_1.Base58.encode(newPubkey)}if((0,ow_1.default)(option,interface_2.ow_ATAOption),!(0,utils_1.isOnCurve)(pk))throw Error(`ArgumentError: token owner cannot be a derived account, got ${bs58_1.Base58.encode(pk)}`);for(let nonce=255;nonce>0;nonce--)try{const programId=Buffer.from(null!==(_a=option.program)&&void 0!==_a?_a:instruction_1.TokenInstruction.TOKEN_PROGRAM_ID,"hex"),associatedProgramId=Buffer.from(instruction_1.TokenInstruction.ASSOCIATED_TOKEN_PROGRAM_ID,"hex"),mint=bs58_1.Base58.decode(option.mintAccount);return bs58_1.Base58.encode((0,utils_1.createProgramAccount)([pk,programId,mint,Buffer.from([nonce])],associatedProgramId))}catch(error){if(error instanceof TypeError)throw error}throw Error("Unable to find a viable program address nonce")}static prepareAddress(path){return this.preparePublickey(path)}static resolveAddress(response,option){const pk=this.resolvePublickey(response);return this.addressConvert(pk,option)}static preparePublickey(path){return(0,ow_1.default)(path,interface_2.ow_path),protocol_transaction_1.SecuxTransactionTool.getPublickey(path,interface_1.EllipticCurve.ED25519)}static resolvePublickey(response){const pk_64=protocol_transaction_1.SecuxTransactionTool.resolvePublickey(response,interface_1.EllipticCurve.ED25519);return Buffer.from(pk_64,"base64").toString("hex")}static prepareSign(feePayer,content){(0,ow_1.default)(feePayer,interface_2.ow_address),(0,ow_1.default)(content,interface_2.ow_txDetail);const tx=new transaction_1.Transaction(content.recentBlockhash);for(const ins of content.instructions){const{type,params}=ins;if(type)tx.addInstruction(interface_2.InstructionMap[type](params));else try{const{programId,keys,data}=ins;tx.addInstruction({programId:(0,utils_1.toPublickey)(programId),accounts:keys.map((x=>Object.assign(Object.assign({},x),{publickey:(0,utils_1.toPublickey)(x.pubkey)}))),data:(0,communication_1.getBuffer)(data)})}catch(_a){tx.addInstruction(ins)}}return tx.dataForSign((0,utils_1.toPublickey)(feePayer)),SecuxSOL.prepareSignSerialized(tx.serialize(),content.ownerships,{txType:content.txType})}static prepareSignSerialized(transaction,ownerships,option){var _a;(0,utility_1.checkFWVersion)("mcu",mcu[transport_1.ITransport.deviceType],transport_1.ITransport.mcuVersion),(0,utility_1.checkFWVersion)("se","1.93",transport_1.ITransport.seVersion),(0,ow_1.default)(transaction,communication_1.ow_communicationData),(0,ow_1.default)(ownerships,ow_1.default.array.ofType(interface_2.ow_ownership).nonEmpty),option&&(0,ow_1.default)(option,interface_2.ow_txOption);const tx=transaction_1.Transaction.from((0,communication_1.getBuffer)(transaction)),signers=tx.Signers.map((x=>SecuxSOL.addressConvert(x)));signers.length<ownerships.length&&(null==logger||logger.warn(`expect ${signers.length} signers, but got ${ownerships.length}`));const checks={};signers.forEach((account=>checks[account]=""));const paths=[];for(const owner of ownerships){let check=checks[owner.account];void 0!==check&&(check||(checks[owner.account]=owner.path,paths.push(owner.path)))}for(const account of Object.keys(checks))checks[account]||null==logger||logger.warn(`bip-32 path of account "${account}" not found`);const sigData=tx.dataForSign(null==option?void 0:option.feePayer),txs=paths.map((_=>sigData)),commandData=protocol_transaction_1.SecuxTransactionTool.signRawTransactionList(paths,txs,void 0,{tp:null!==(_a=null==option?void 0:option.txType)&&void 0!==_a?_a:interface_1.TransactionType.NORMAL,curve:interface_1.EllipticCurve.ED25519}),serialized=Buffer.from(JSON.stringify({rawTx:sigData.toString("hex"),map:ownerships.map((x=>(0,utils_1.toPublickey)(x.account)))}));return(0,communication_1.wrapResult)({commandData,serialized:(0,communication_1.toCommunicationData)(serialized)})}static prepareSignMessage(path,message){let buffer;return(0,utility_1.checkFWVersion)("mcu",{crypto:"2.24",nifty:"2.06"}[transport_1.ITransport.deviceType],transport_1.ITransport.mcuVersion),(0,ow_1.default)(path,interface_2.ow_path),(0,ow_1.default)(message,ow_1.default.any(ow_1.default.string.nonEmpty,ow_1.default.buffer)),"string"==typeof message&&(buffer=message.startsWith("0x")?Buffer.from(message.slice(2),"hex"):Buffer.from(message)),protocol_transaction_1.SecuxTransactionTool.signMessage(path,null!=buffer?buffer:message,{curve:interface_1.EllipticCurve.ED25519_RAW})}static resolveSignature(response){return Buffer.from(protocol_transaction_1.SecuxTransactionTool.resolveSignature(response),"base64").slice(0,-1).toString("base64")}static resolveSignatureList(response){return getSignatures(response).map((x=>x.toString("base64")))}static resolveTransaction(response,serialized){const sigs=getSignatures(response),{rawTx,map}=JSON.parse((0,communication_1.getBuffer)(serialized).toString());if(sigs.length!==map.length)throw Error(`expect ${map.length} signatures, but got ${sigs.length}`);const tx=transaction_1.Transaction.fromMessage(Buffer.from(rawTx,"hex"));for(let i=0;i<sigs.length;i++)tx.addSignature(map[i],sigs[i]);return tx.serialize().toString("hex")}static async getAddress(path,option){const data=SecuxSOL.prepareAddress(path),rsp=await this.Exchange((0,communication_1.getBuffer)(data));return SecuxSOL.resolveAddress(rsp,option)}static async getPublickey(path){const data=SecuxSOL.preparePublickey(path),rsp=await this.Exchange((0,communication_1.getBuffer)(data));return SecuxSOL.resolvePublickey(rsp)}static async getXPublickey(path){throw Error("Solana(SOL) do not support xpub.")}static async sign(...args){try{(0,ow_1.default)(args[0],interface_2.ow_path);const data=SecuxSOL.prepareSignMessage(args[0],args[1]),rsp=await this.Exchange((0,communication_1.getBuffer)(data));return{raw_tx:void 0,signature:SecuxSOL.resolveSignature(rsp)}}catch(error){if(!(error instanceof ow_2.ArgumentError))throw error}try{const{commandData,serialized}=SecuxSOL.prepareSignSerialized(args[0],args[1],args[2]),rsp=await this.Exchange((0,communication_1.getBuffer)(commandData));return{raw_tx:SecuxSOL.resolveTransaction(rsp,serialized)}}catch(error){if(!(error instanceof ow_2.ArgumentError))throw error}for(const owner of args[1].ownerships)owner.account||(owner.account=await SecuxSOL.getAddress.call(this,owner.path));const{commandData,serialized}=SecuxSOL.prepareSign(args[0],args[1]),rsp=await this.Exchange((0,communication_1.getBuffer)(commandData));return{raw_tx:SecuxSOL.resolveTransaction(rsp,serialized)}}}function getSignatures(response){return protocol_transaction_1.SecuxTransactionTool.resolveSignatureList(response).map((x=>Buffer.from(x,"base64"))).map((x=>utility_1.Signature.fromSignature(x))).map((x=>Buffer.concat([x.r,x.s])))}exports.SecuxSOL=SecuxSOL,(0,utility_1.loadPlugin)(SecuxSOL,"SecuxSOL");