@@ -3180,6 +3180,69 @@ describe('V2 Wallet:', function () {
31803180 intent . intentType . should . equal ( 'fillNonce' ) ;
31813181 } ) ;
31823182
3183+ it ( 'populate intent should return valid eth tokenApproval intent' , async function ( ) {
3184+ const mpcUtils = new ECDSAUtils . EcdsaUtils ( bitgo , bitgo . coin ( 'hteth' ) ) ;
3185+ const feeOptions = {
3186+ maxFeePerGas : 3000000000 ,
3187+ maxPriorityFeePerGas : 2000000000 ,
3188+ } ;
3189+ const tokenName = 'usdc' ;
3190+
3191+ const intent = mpcUtils . populateIntent ( bitgo . coin ( 'hteth' ) , {
3192+ reqId,
3193+ intentType : 'tokenApproval' ,
3194+ tokenName,
3195+ feeOptions,
3196+ } ) ;
3197+
3198+ intent . should . have . property ( 'recipients' , undefined ) ;
3199+ intent . feeOptions ! . should . deepEqual ( feeOptions ) ;
3200+ intent . tokenName ! . should . equal ( tokenName ) ;
3201+ intent . intentType . should . equal ( 'tokenApproval' ) ;
3202+ } ) ;
3203+
3204+ it ( 'populate intent should return valid polygon tokenApproval intent' , async function ( ) {
3205+ const mpcUtils = new ECDSAUtils . EcdsaUtils ( bitgo , bitgo . coin ( 'tpolygon' ) ) ;
3206+ const feeOptions = {
3207+ maxFeePerGas : 3000000000 ,
3208+ maxPriorityFeePerGas : 2000000000 ,
3209+ } ;
3210+ const tokenName = 'usdt' ;
3211+
3212+ const intent = mpcUtils . populateIntent ( bitgo . coin ( 'tpolygon' ) , {
3213+ reqId,
3214+ intentType : 'tokenApproval' ,
3215+ tokenName,
3216+ feeOptions,
3217+ } ) ;
3218+
3219+ intent . should . have . property ( 'recipients' , undefined ) ;
3220+ intent . feeOptions ! . should . deepEqual ( feeOptions ) ;
3221+ intent . tokenName ! . should . equal ( tokenName ) ;
3222+ intent . intentType . should . equal ( 'tokenApproval' ) ;
3223+ } ) ;
3224+
3225+ it ( 'populate intent should return valid bsc tokenApproval intent' , async function ( ) {
3226+ const mpcUtils = new ECDSAUtils . EcdsaUtils ( bitgo , bitgo . coin ( 'tbsc' ) ) ;
3227+ const feeOptions = {
3228+ maxFeePerGas : 3000000000 ,
3229+ maxPriorityFeePerGas : 2000000000 ,
3230+ } ;
3231+ const tokenName = 'busd' ;
3232+
3233+ const intent = mpcUtils . populateIntent ( bitgo . coin ( 'tbsc' ) , {
3234+ reqId,
3235+ intentType : 'tokenApproval' ,
3236+ tokenName,
3237+ feeOptions,
3238+ } ) ;
3239+
3240+ intent . should . have . property ( 'recipients' , undefined ) ;
3241+ intent . feeOptions ! . should . deepEqual ( feeOptions ) ;
3242+ intent . tokenName ! . should . equal ( tokenName ) ;
3243+ intent . intentType . should . equal ( 'tokenApproval' ) ;
3244+ } ) ;
3245+
31833246 it ( 'should populate intent with custodianTransactionId' , async function ( ) {
31843247 const mpcUtils = new ECDSAUtils . EcdsaUtils ( bitgo , bitgo . coin ( 'hteth' ) ) ;
31853248 const feeOptions = {
@@ -4942,4 +5005,99 @@ describe('V2 Wallet:', function () {
49425005 . should . be . rejectedWith ( 'invalid argument for amount - Integer greater than zero or numeric string expected' ) ;
49435006 } ) ;
49445007 } ) ;
5008+
5009+ describe ( 'Token Approval' , function ( ) {
5010+ let ethWallet ;
5011+ const tokenName = 'usdc' ;
5012+ const walletPassphrase = 'test_passphrase' ;
5013+
5014+ before ( async function ( ) {
5015+ const walletData = {
5016+ id : '598f606cd8fc24710d2ebadb1d9459bb' ,
5017+ coin : 'teth' ,
5018+ keys : [
5019+ '598f606cd8fc24710d2ebad89dce86c2' ,
5020+ '598f606cc8e43aef09fcb785221d9dd2' ,
5021+ '5935d59cf660764331bafcade1855fd7' ,
5022+ ] ,
5023+ } ;
5024+ ethWallet = new Wallet ( bitgo , bitgo . coin ( 'teth' ) , walletData ) ;
5025+ } ) ;
5026+
5027+ it ( 'should successfully approve ERC20 token' , async function ( ) {
5028+ const mockTokenApprovalBuild = {
5029+ txPrebuild : {
5030+ txHex : '0x1234567890abcdef' ,
5031+ txInfo : {
5032+ gasPrice : 20000000000 ,
5033+ gasLimit : 60000 ,
5034+ nonce : 1 ,
5035+ } ,
5036+ } ,
5037+ coin : 'teth' ,
5038+ tokenName : tokenName ,
5039+ } ;
5040+
5041+ const mockSignedTransaction = {
5042+ txHex : '0xabcdef1234567890' ,
5043+ halfSigned : {
5044+ txHex : '0xabcdef1234567890' ,
5045+ } ,
5046+ } ;
5047+
5048+ const mockSentTransaction = {
5049+ hash : '0x9876543210fedcba' ,
5050+ status : 'signed' ,
5051+ } ;
5052+
5053+ // Mock the token approval build endpoint
5054+ const buildScope = nock ( bgUrl )
5055+ . post ( `/api/v2/teth/wallet/${ ethWallet . id ( ) } /token/approval/build` )
5056+ . reply ( 200 , mockTokenApprovalBuild ) ;
5057+
5058+ // Mock getKeychainsAndValidatePassphrase
5059+ sinon . stub ( ethWallet , 'getKeychainsAndValidatePassphrase' ) . resolves ( [
5060+ {
5061+ id : '598f606cd8fc24710d2ebad89dce86c2' ,
5062+ prv : 'test_private_key' ,
5063+ } ,
5064+ ] ) ;
5065+
5066+ // Mock signTransaction
5067+ sinon . stub ( ethWallet , 'signTransaction' ) . resolves ( mockSignedTransaction ) ;
5068+
5069+ // Mock sendTransaction
5070+ sinon . stub ( ethWallet , 'sendTransaction' ) . resolves ( mockSentTransaction ) ;
5071+
5072+ const result = await ethWallet . approveErc20Token ( walletPassphrase , tokenName ) ;
5073+
5074+ result . should . equal ( mockSentTransaction ) ;
5075+ buildScope . isDone ( ) . should . be . true ( ) ;
5076+ } ) ;
5077+
5078+ it ( 'should handle token approval build failure' , async function ( ) {
5079+ const buildScope = nock ( bgUrl )
5080+ . post ( `/api/v2/teth/wallet/${ ethWallet . id ( ) } /token/approval/build` )
5081+ . reply ( 400 , { error : 'Invalid token name' } ) ;
5082+
5083+ sinon . stub ( ethWallet , 'getKeychainsAndValidatePassphrase' ) . resolves ( [
5084+ {
5085+ id : '598f606cd8fc24710d2ebad89dce86c2' ,
5086+ prv : 'test_private_key' ,
5087+ } ,
5088+ ] ) ;
5089+
5090+ await ethWallet . approveErc20Token ( walletPassphrase , 'invalid_token' ) . should . be . rejectedWith ( 'Invalid token name' ) ;
5091+
5092+ buildScope . isDone ( ) . should . be . true ( ) ;
5093+ } ) ;
5094+
5095+ it ( 'should validate required parameters for approveErc20Token' , async function ( ) {
5096+ await ethWallet . approveErc20Token ( '' , tokenName ) . should . be . rejectedWith ( ) ;
5097+ } ) ;
5098+
5099+ afterEach ( function ( ) {
5100+ sinon . restore ( ) ;
5101+ } ) ;
5102+ } ) ;
49455103} ) ;
0 commit comments